From 8773b83d478cc627ff95386bce59387033a844be Mon Sep 17 00:00:00 2001 From: Alexander Kuechler Date: Tue, 12 Sep 2023 11:05:06 +0200 Subject: [PATCH] Minor fixes to the broken EOG --- .../aisec/cpg/helpers/SubgraphWalker.kt | 35 ++++++++++++++++- .../cpg/passes/EvaluationOrderGraphPass.kt | 39 ++++++++++++++++--- .../aisec/cpg/passes/GoExtraPass.kt | 3 +- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt index afcaaf7ab6..3e17884498 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt @@ -29,10 +29,14 @@ import de.fraunhofer.aisec.cpg.ScopeManager import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.AST import de.fraunhofer.aisec.cpg.graph.Node +import de.fraunhofer.aisec.cpg.graph.allChildren import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge.Companion.checkForPropertyEdge import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge.Companion.unwrap +import de.fraunhofer.aisec.cpg.graph.statements.expressions.ConstructExpression +import de.fraunhofer.aisec.cpg.graph.statements.expressions.LambdaExpression +import de.fraunhofer.aisec.cpg.passes.ResolutionStartHolder import de.fraunhofer.aisec.cpg.processing.strategy.Strategy import java.lang.annotation.AnnotationFormatError import java.lang.reflect.Field @@ -316,7 +320,36 @@ object SubgraphWalker { Consumer { c: BiConsumer -> c.accept(current, parent) } ) val unseenChildren = - strategy(current).asSequence().filter { it !in seen }.toList() + strategy(current).asSequence().filter { it !in seen }.toMutableList() + + if ( + strategy == Strategy::EOG_FORWARD && + current is LambdaExpression && + current.function?.let { it !in unseenChildren } == true + ) { + // Check if there are AST children which aren't reachable through the + // EOG. If so, add them to the unseenChildren. + unseenChildren.addAll( + current.function + .allChildren() + .flatMap { it.resolutionStartNodes } + .toSet() + ) + } + + if ( + strategy == Strategy::EOG_FORWARD && + current is ConstructExpression && + current.anoymousClass != null + ) { + unseenChildren.addAll( + current.anoymousClass + .allChildren() + .flatMap { it.resolutionStartNodes } + .toSet() + ) + } + seen.addAll(unseenChildren) unseenChildren.asReversed().forEach { child: Node -> (todo as ArrayDeque>).push(Pair(child, current)) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt index 9d85400f09..2cc1e029b8 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt @@ -178,7 +178,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa /** * Removes EOG edges by first building the negative set of nodes that cannot be visited and then - * remove there outgoing edges. This also removes cycles. + * remove their outgoing edges. This also removes cycles. */ protected fun removeUnreachableEOGEdges(tu: TranslationUnitDeclaration) { // All nodes which have an eog edge @@ -200,9 +200,11 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa } .toSet() // Remove all nodes from eogNodes which are reachable from validStarts and transitively. + val alreadySeen = IdentitySet() while (validStarts.isNotEmpty()) { eogNodes.removeAll(validStarts) - validStarts = validStarts.flatMap { it.nextEOG }.filter { it in eogNodes }.toSet() + validStarts = validStarts.flatMap { it.nextEOG }.filter { it !in alreadySeen }.toSet() + alreadySeen.addAll(validStarts) } // The remaining nodes are unreachable from the entry points. We delete their outgoing EOG // edges. @@ -211,7 +213,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa next.end.removePrevEOGEntry(unvisitedNode) } - unvisitedNode.nextEOGEdges.clear() + unvisitedNode.clearNextEOG() } } @@ -521,8 +523,13 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa // Handle left hand side(s) first node.lhs.forEach { createEOG(it) } - // Then the right side(s) - node.rhs.forEach { createEOG(it) } + // Then the right side(s). Avoid creating the EOG twice if it's already part of the + // initializer of a declaration + node.rhs.forEach { + if (it !in node.declarations.map { decl -> decl.initializer }) { + createEOG(it) + } + } pushToEOG(node) } @@ -739,6 +746,28 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa createEOG(arg) } pushToEOG(node) + + if (node.anoymousClass != null) { + // Generate the EOG inside the anonymous class. It's not linked to the EOG of the outer + // part. + val tmpCurrentEOG = currentPredecessors.toMutableList() + val tmpCurrentProperties = nextEdgeProperties.toMutableMap() + val tmpIntermediateNodes = intermediateNodes.toMutableList() + + nextEdgeProperties.clear() + currentPredecessors.clear() + intermediateNodes.clear() + + createEOG(node.anoymousClass) + + nextEdgeProperties.clear() + currentPredecessors.clear() + intermediateNodes.clear() + + nextEdgeProperties.putAll(tmpCurrentProperties) + currentPredecessors.addAll(tmpCurrentEOG) + intermediateNodes.addAll(tmpIntermediateNodes) + } } /** diff --git a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/GoExtraPass.kt b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/GoExtraPass.kt index bb73413a02..4dda626bc0 100644 --- a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/GoExtraPass.kt +++ b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/GoExtraPass.kt @@ -103,6 +103,7 @@ import de.fraunhofer.aisec.cpg.passes.order.ExecuteBefore * [CallResolver] and convert certain [CallExpression] nodes into a [CastExpression]. */ @ExecuteBefore(SymbolResolver::class) +@ExecuteBefore(EvaluationOrderGraphPass::class) @ExecuteBefore(DFGPass::class) class GoExtraPass(ctx: TranslationContext) : ComponentPass(ctx), ScopeProvider { @@ -177,7 +178,7 @@ class GoExtraPass(ctx: TranslationContext) : ComponentPass(ctx), ScopeProvider { // And try to resolve it val ref = scopeManager.resolveReference(expr) if (ref == null) { - // We need to implicitly declare it, if its not declared before. + // We need to implicitly declare it, if it's not declared before. val decl = newVariableDeclaration(expr.name, expr.autoType()) decl.location = expr.location decl.isImplicit = true