Move Branching EOG Edges and needed DF Edge from CF Nodes to their condition#2749
Open
konradweiss wants to merge 18 commits into
Open
Move Branching EOG Edges and needed DF Edge from CF Nodes to their condition#2749konradweiss wants to merge 18 commits into
konradweiss wants to merge 18 commits into
Conversation
…to solve the issue arrising with them being expressions
…ngle node to start the eog
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Evaluation Order Graph (EOG) model for branching constructs by moving branching EOG edges (and previously-added DFG edges) away from control-flow (CF) nodes and onto their actual branching sub-nodes (conditions / selector / foreach variable), to avoid issues when branching statements are represented as expressions and to better preserve indirect data-flow behavior.
Changes:
- Adjust EOG construction for branching constructs (If/Conditional/Loops/Switch/Synchronized) so branching happens at the condition/selector/variable node and merge happens at the parent node.
- Remove DFG edges from branching parent nodes to their conditions/selectors that were previously added for “mutually exclusive branching expressions”.
- Update control-dependence, unreachability analysis, abstract evaluation utilities, docs, and tests to match the new EOG shape.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/docs/CPG/specs/eog.md | Updates EOG specification diagrams for affected branching constructs. |
| cpg-language-java/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/EOGTest.kt | Adjusts Java EOG tests to assert branching at condition nodes and merge at parent. |
| cpg-language-cxx/src/test/resources/c/switch_eog.c | Minor test resource comment formatting update. |
| cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/StronglyConnectedComponentTest.kt | Updates SCC assertions to use loop condition nodes as branching points. |
| cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/EOGTest.kt | Adjusts C++ EOG tests to the new branching/merge locations. |
| cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPassTest.kt | Updates pass-level EOG tests for loops/foreach semantics under the new model. |
| cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPassTest.kt | Updates CDG expectations to depend on condition/foreach-variable rather than parent CF node. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/Pass.kt | Adds per-pass execution print statements during sequential pass execution. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt | Core change: moves attach/branching logic so branching edges originate from condition/selector/variable nodes. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/DFGPass.kt | Removes calls that added DFG edges from branching parents to their conditions/selectors. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPass.kt | Updates conditional-branch detection to align with branching-at-condition representation. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/Util.kt | Removes the helper for adding DFG edges for mutually exclusive branching expressions. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/functional/BasicLatticesRedesign.kt | Updates loop-branch detection to use the new “branch node” identification. |
| cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/EvaluationExtensions.kt | Adds Node.branchOf(...) helper for detecting branching nodes. |
| cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/UnreachableEOGPassTest.kt | Updates unreachability tests to look at outgoing edges of condition nodes. |
| cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/UnreachableEOGPass.kt | Switches unreachability propagation to branch from condition nodes rather than parent nodes. |
| cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/abstracteval/value/IntegerValue.kt | Adapts interval refinement to treat the condition node as the branch point. |
Comment on lines
339
to
+342
| // Execute it | ||
| println("Executing: ${pass.simpleName}") | ||
| executePass(pass, ctx, result, executedFrontends) | ||
|
|
||
| println("Finished: ${pass.simpleName}") |
| child1 --EOG:false--> parent(["While"]) | ||
| child1 --EOG:true--> child3["statement"] | ||
| child3 --EOG--> child1 | ||
| parent --> next:::outer |
| @@ -1073,20 +1071,20 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa | |||
| handleEOG(node.elseExpression) | |||
| openBranchNodes.addAll(currentPredecessors) | |||
| setCurrentEOGs(openBranchNodes) | |||
Comment on lines
1165
to
1167
| node.elseStatement?.let { handleEOG(it) } | ||
| handleContainedBreaksAndContinues(node) | ||
| nextEdgeBranch = false |
Comment on lines
1171
to
1191
| @@ -1178,7 +1174,6 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa | |||
| handleEOG(node.conditionDeclaration) | |||
| handleEOG(node.condition) | |||
|
|
|||
| attachToEOG(node) // To have semantic information after the condition evaluation | |||
| nextEdgeBranch = true | |||
| val tmpEOGNodes = currentPredecessors.toMutableList() | |||
|
|
|||
| @@ -1192,6 +1187,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa | |||
| node.elseStatement?.let { handleEOG(it) } | |||
| handleContainedBreaksAndContinues(node) | |||
| nextEdgeBranch = false | |||
| attachToEOG(node) | |||
| } | |||
Comment on lines
1193
to
1213
| @@ -1200,7 +1196,6 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa | |||
| handleEOG(node.initializerStatement) | |||
| handleEOG(node.conditionDeclaration) | |||
| handleEOG(node.condition) | |||
| attachToEOG(node) // To have semantic information after the condition evaluation | |||
| val openConditionEOGs = currentPredecessors.toMutableList() | |||
| nextEdgeBranch = true | |||
| handleEOG(node.thenStatement) | |||
| @@ -1214,6 +1209,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa | |||
| openBranchNodes.addAll(openConditionEOGs) | |||
| } | |||
| setCurrentEOGs(openBranchNodes) | |||
| attachToEOG(node) | |||
| } | |||
Comment on lines
339
to
388
| /** | ||
| * Adds the DFG edge from [For.condition] or [For.conditionDeclaration] to the [For] to show the | ||
| * dependence between data and the branching node. Usage of one or the other in the statement is | ||
| * mutually exclusive. | ||
| */ | ||
| protected fun handleFor(node: For) { | ||
| Util.addDFGEdgesForMutuallyExclusiveBranchingExpression( | ||
| node, | ||
| node.condition, | ||
| node.conditionDeclaration, | ||
| ) | ||
|
|
||
| if (node.usedAsExpression) { | ||
| node.statement?.let { node.prevDFGEdges += it } | ||
| node.elseStatement?.let { node.prevDFGEdges += it } | ||
| } | ||
| handleBreakableNodesAsExpressions(node) | ||
| } | ||
|
|
||
| /** | ||
| * Adds the DFG edge from [IfElse.condition] or [IfElse.conditionDeclaration] to the [IfElse] to | ||
| * show the dependence between data and the branching node. Usage of one or the other in the | ||
| * statement is mutually exclusive. | ||
| */ | ||
| protected fun handleIfElse(node: IfElse) { | ||
| Util.addDFGEdgesForMutuallyExclusiveBranchingExpression( | ||
| node, | ||
| node.condition, | ||
| node.conditionDeclaration, | ||
| ) | ||
|
|
||
| if (node.usedAsExpression) { | ||
| node.thenStatement?.let { node.prevDFGEdges += it } | ||
| node.elseStatement?.let { node.prevDFGEdges += it } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Adds the DFG edge from [Switch.selector] or [Switch.selectorDeclaration] to the [Switch] to | ||
| * show the dependence between data and the branching node. Usage of one or the other in the | ||
| * statement is mutually exclusive. | ||
| */ | ||
| protected fun handleSwitch(node: Switch) { | ||
| Util.addDFGEdgesForMutuallyExclusiveBranchingExpression( | ||
| node, | ||
| node.selector, | ||
| node.selectorDeclaration, | ||
| ) | ||
| if (node.usedAsExpression) { | ||
| node.statement?.let { | ||
| node.prevDFGEdges += it | ||
| it.usedAsExpression = true | ||
| } | ||
| } | ||
| handleBreakableNodesAsExpressions(node) | ||
| } | ||
|
|
||
| /** | ||
| * Adds the DFG edge from [While.condition] or [While.conditionDeclaration] to the [While] to | ||
| * show the dependence between data and the branching node. Usage of one or the other in the | ||
| * statement is mutually exclusive. | ||
| */ | ||
| protected fun handleWhile(node: While) { | ||
| Util.addDFGEdgesForMutuallyExclusiveBranchingExpression( | ||
| node, | ||
| node.condition, | ||
| node.conditionDeclaration, | ||
| ) | ||
|
|
||
| if (node.usedAsExpression) { |
Comment on lines
113
to
+124
| @Test | ||
| fun testIfFalse() { | ||
| val method = tu.functions["ifFalse"] | ||
| assertNotNull(method) | ||
|
|
||
| val ifStatement = method.ifs.firstOrNull() | ||
| assertNotNull(ifStatement) | ||
|
|
||
| assertFalse(ifStatement.nextEOGEdges[1].unreachable) | ||
| assertTrue(ifStatement.nextEOGEdges[0].unreachable) | ||
| ifStatement.condition?.let { | ||
| assertFalse(it.nextEOGEdges[1].unreachable) | ||
| assertTrue(it.nextEOGEdges[0].unreachable) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Removing DF Edge from branching condition to CFG Nodes in an attempt to solve the issue arising with them being expressions. This also requires to move the branching eog edges from the CF node to the condition, to continue capturing indirect data flows. We will change:
Do,While,IfElse,For,ForEach,Conditional,SwitchandSynchronizedThe


IfElsewill no longer be evaluated as follows:but will look like this:
In the case of a while loop it will no longer look like this:

instead it will look like this:
