Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DFG of the variable of aForEachStatement #1052

Merged
merged 16 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions cpg-core/specifications/dfg.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,17 +405,33 @@ Scheme:
## ForEachStatement

Interesting fields:

* `variable: Statement`: The statement which is used in each iteration to assign the current iteration value
* `iterable: Statement`: The statement or expression, which is iterated

Scheme:
```mermaid
flowchart LR
node([ForEachStatement]) -.- variable(variable)
node -.- iterable(iterable)
node([ForEachStatement]) -.- variable[variable]
node -.- iterable[iterable]
iterable -- DFG --> variable
```

## DeclarationStatement

Interesting fields:

* `declarations: List<Declaration>`: All the declarations which are contained in this statement.

The value of the statement (which serves as a wrapper around the individual declarations) flows into the declarations.

Scheme:
```mermaid
flowchart LR
node([DeclarationStatement]) -.- declarations["for all i: declarations[i]"]
node -- DFG --> declarations
```

## FunctionDeclaration

Interesting fields:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import de.fraunhofer.aisec.cpg.graph.edge.Properties
import de.fraunhofer.aisec.cpg.graph.statements.*
import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator
import de.fraunhofer.aisec.cpg.graph.statements.expressions.DeclaredReferenceExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.UnaryOperator
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker.IterativeGraphWalker
import de.fraunhofer.aisec.cpg.passes.order.DependsOn
Expand Down Expand Up @@ -206,6 +207,23 @@ open class ControlFlowSensitiveDFGPass : Pass() {
previousWrites[currentNode.refersTo]?.lastOrNull()?.let {
currentNode.addPrevDFG(it)
}
} else if (currentNode is ForEachStatement) {
// The VariableDeclaration in the ForEachStatement doesn't have an initializer, so
// the "normal" case won't work. We handle this case separately here...

// This is what we write to the declaration
val iterable = currentNode.iterable as? Expression

// We wrote something to this variable declaration
writtenDecl =
(currentNode.variable as? DeclarationStatement)?.singleDeclaration
as? VariableDeclaration

writtenDecl?.let { wd ->
iterable?.let { wd.addPrevDFG(it) }
// Add the variable declaration to the list of previous write nodes in this path
previousWrites[wd] = mutableListOf(wd)
}
}

// Check for loops: No loop statement with the same state as before and no write which
KuechA marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
11 changes: 11 additions & 0 deletions cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/DFGPass.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import de.fraunhofer.aisec.cpg.graph.declarations.FieldDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.CompoundStatement
import de.fraunhofer.aisec.cpg.graph.statements.DeclarationStatement
import de.fraunhofer.aisec.cpg.graph.statements.ForEachStatement
import de.fraunhofer.aisec.cpg.graph.statements.ReturnStatement
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
Expand Down Expand Up @@ -81,6 +82,7 @@ class DFGPass : Pass() {
// Statements
is ReturnStatement -> handleReturnStatement(node)
is ForEachStatement -> handleForEachStatement(node)
is DeclarationStatement -> handleDeclarationStatement(node)
// Declarations
is FieldDeclaration -> handleFieldDeclaration(node)
is FunctionDeclaration -> handleFunctionDeclaration(node)
Expand All @@ -90,6 +92,15 @@ class DFGPass : Pass() {
}
}

/**
* For a [DeclarationStatement], the whole statement flows into its declarations. This is fine
* because it's used as a wrapper if a Statement is needed but we only have a Declaration (which
* is not a statement).
*/
private fun handleDeclarationStatement(node: DeclarationStatement) {
KuechA marked this conversation as resolved.
Show resolved Hide resolved
node.declarations.forEach { it.addPrevDFG(node) }
}

/**
* For a [MemberExpression], the base flows to the expression if the field is not implemented in
* the code under analysis. Otherwise, it's handled as a [DeclaredReferenceExpression].
Expand Down