Fraunhofer-AISEC / cpg

A library to extract Code Property Graphs from C/C++, Java, Go, Python, Ruby and every other language through LLVM-IR.
https://fraunhofer-aisec.github.io/cpg/
Apache License 2.0
246 stars 59 forks source link

Adding soft from DynamicInvokeResolver to ControlFlowSensitiveDFGPass #1532

Closed konradweiss closed 1 month ago

konradweiss commented 1 month ago

Solves #1531

konradweiss commented 1 month ago

Apparently there is now a problem with dependency ordering between passes. We have to solve that before this can be merged.

oxisto commented 1 month ago

Apparently there is now a problem with dependency ordering between passes. We have to solve that before this can be merged.

Hm yes it looks like the dependency matching algorithm is aborting because the ControlFlowSensitiveDFGPass is not registered in the test; but you explicitly added it as a "soft" dependency, so looks like this is broken :(

oxisto commented 1 month ago

Can you try with the following patch?

diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDependencies.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDependencies.kt
index 4ee5f627d..50ff80b02 100644
--- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDependencies.kt
+++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDependencies.kt
@@ -64,4 +64,32 @@ data class PassWithDependencies(
         }
         return builder.toString()
     }
+
+    /**
+     * Checks whether the [dependencies] of this pass are met. The list of [softDependencies] and
+     * [hardDependencies] is removed step-by-step in
+     * [PassWithDepsContainer.getAndRemoveFirstPassWithoutDependencies].
+     */
+    fun dependenciesMet(workingList: MutableList<PassWithDependencies>): Boolean {
+        // In the simplest case all our dependencies are empty since they were already removed by
+        // the selecting algorithm.
+        if (this.dependencies.isEmpty() && !this.isLastPass) {
+            return true
+        }
+
+        // We also need to check, whether we still "soft" depend on passes that are just not
+        // there (after all hard dependencies are met), in this case we can select the pass
+        // as well
+        val remainingClasses = workingList.map { it.pass }
+        if (
+            this.hardDependencies.isEmpty() &&
+                this.softDependencies.all { !remainingClasses.contains(it) } &&
+                !this.isLastPass
+        ) {
+            return true
+        }
+
+        // Otherwise, we still depend on an unselected pass
+        return false
+    }
 }
diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDepsContainer.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDepsContainer.kt
index e6b5988fb..c3219e55c 100644
--- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDepsContainer.kt
+++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/configuration/PassWithDepsContainer.kt
@@ -160,9 +160,8 @@ class PassWithDepsContainer {

             // Keep going until our dependencies are met, this will collect passes that can run in
             // parallel in results
-            if (
-                currentElement.dependencies.isEmpty() && !currentElement.isLastPass
-            ) { // no unsatisfied dependencies
+            if (currentElement.dependenciesMet(workingList)) {
+                // no unsatisfied dependencies
                 val result = currentElement.pass
                 results.add(result)
sonarcloud[bot] commented 1 month ago

Quality Gate Passed Quality Gate passed

Issues
1 New issue
0 Accepted issues

Measures
0 Security Hotspots
100.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarCloud