From 76048619c1926ff1893587068c4b5550669db82b Mon Sep 17 00:00:00 2001 From: Tobias Specht Date: Thu, 27 Jan 2022 12:20:08 +0100 Subject: [PATCH] Add test cases for CXX ambiguities (#682) * Add test case for function pointer vs type cast ambiguity * Add test case MemberCallExpression vs CallExpression ambiguity * Update README.md Co-authored-by: Christian Banse --- README.md | 1 + .../cpg/frontends/cpp/CXXAmbiguitiesTest.kt | 61 +++++++++++++++++++ .../resources/function_ptr_or_type_cast.c | 22 +++++++ .../resources/method_or_function_call.cpp | 27 ++++++++ 4 files changed, 111 insertions(+) create mode 100644 cpg-core/src/test/resources/function_ptr_or_type_cast.c create mode 100644 cpg-core/src/test/resources/method_or_function_call.cpp diff --git a/README.md b/README.md index e5a97d2078..1ce2a109fb 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ The following authors have contributed to this project (in alphabetical order): * [maximiliankaul](https://github.com/maximiliankaul) * [obraunsdorf](https://github.com/obraunsdorf) * [oxisto](https://github.com/oxisto) +* [peckto](https://github.com/peckto) * [titze](https://github.com/titze) * [vfsrfs](https://github.com/vfsrfs) diff --git a/cpg-core/src/test/java/de/fraunhofer/aisec/cpg/frontends/cpp/CXXAmbiguitiesTest.kt b/cpg-core/src/test/java/de/fraunhofer/aisec/cpg/frontends/cpp/CXXAmbiguitiesTest.kt index 44421f48b2..e990e8ecc1 100644 --- a/cpg-core/src/test/java/de/fraunhofer/aisec/cpg/frontends/cpp/CXXAmbiguitiesTest.kt +++ b/cpg-core/src/test/java/de/fraunhofer/aisec/cpg/frontends/cpp/CXXAmbiguitiesTest.kt @@ -28,10 +28,14 @@ package de.fraunhofer.aisec.cpg.frontends.cpp import de.fraunhofer.aisec.cpg.TestUtils import de.fraunhofer.aisec.cpg.graph.bodyOrNull import de.fraunhofer.aisec.cpg.graph.byNameOrNull +import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.ProblemDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.statements.DeclarationStatement +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CastExpression +import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberCallExpression import java.io.File import kotlin.test.assertContains import kotlin.test.assertEquals @@ -76,4 +80,61 @@ class CXXAmbiguitiesTest { assertNotNull(problem) assertContains(problem.problem, "CDT") } + + /** + * In CXX there is an ambiguity with the statement: "(A)(B);" 1) If A is a function pointer, + * this is a [CallExpression] 2) If A is a type, this is a [CastExpression] + */ + @Test + fun testFunctionCallOrTypeCast() { + val file = File("src/test/resources/function_ptr_or_type_cast.c") + val tu = TestUtils.analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) + assertNotNull(tu) + + val mainFunc = tu.byNameOrNull("main") + assertNotNull(mainFunc) + + val fooFunc = tu.byNameOrNull("foo") + assertNotNull(fooFunc) + + // First two Statements are CallExpressions + val s1 = mainFunc.getBodyStatementAs(1, CallExpression::class.java) + assertNotNull(s1) + assertEquals(s1.invokes.iterator().next(), fooFunc) + + val s2 = mainFunc.getBodyStatementAs(2, CallExpression::class.java) + assertNotNull(s2) + assertEquals(s2.invokes.iterator().next(), fooFunc) + + // Last two Statements are CastExpressions + val s3 = mainFunc.getBodyStatementAs(3, CastExpression::class.java) + assertNotNull(s3) + + val s4 = mainFunc.getBodyStatementAs(4, CastExpression::class.java) + assertNotNull(s4) + } + + /** + * In CXX there is an ambiguity with the statement: "(A.B)(C);" 1) If B is a method, this is a + * [MemberCallExpression] 2) if B is a function pointer, this is a [CallExpression]. + * + * Function pointer as a struct member are currently not supported in the cpg. This test case + * will just ensure that there will be no crash when parsing such a statement. When adding this + * functionality in the cpg, this test case must be adapted accordingly. + */ + @Test + fun testMethodOrFunction() { + val file = File("src/test/resources/method_or_function_call.cpp") + val tu = TestUtils.analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) + assertNotNull(tu) + + val mainFunc = tu.byNameOrNull("main") + assertNotNull(mainFunc) + + val classA = tu.byNameOrNull("A") + assertNotNull(classA) + + val structB = tu.byNameOrNull("B") + assertNotNull(structB) + } } diff --git a/cpg-core/src/test/resources/function_ptr_or_type_cast.c b/cpg-core/src/test/resources/function_ptr_or_type_cast.c new file mode 100644 index 0000000000..d5f437e037 --- /dev/null +++ b/cpg-core/src/test/resources/function_ptr_or_type_cast.c @@ -0,0 +1,22 @@ +void foo(int i) { +} + +struct S { + int a; +} typedef s_t; + +typedef s_t* s_t_p; + +int main() { + void (*ptr)(int) = &foo; + + // this is a function call + (*ptr)(1); + (ptr)(2); + + // this is a type case + (int)(3); + (s_t_p)(4); + + return 0; +} diff --git a/cpg-core/src/test/resources/method_or_function_call.cpp b/cpg-core/src/test/resources/method_or_function_call.cpp new file mode 100644 index 0000000000..c12651c89c --- /dev/null +++ b/cpg-core/src/test/resources/method_or_function_call.cpp @@ -0,0 +1,27 @@ +struct A { + void foo(int i) { + } +}; + +struct B { + void (*bar)(int); +}; + +void bar(int i) { +} + +int main() { + A a; + B b; + b.bar = &bar; + + // foo is a method + (a.foo)(1); + a.foo(2); + + // bar is a function + (b.bar)(3); + (*b.bar)(3); + + return 0; +}