Skip to content

Commit

Permalink
Improved property edges (#1642)
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto authored Aug 9, 2024
1 parent 0389db4 commit c12deb6
Show file tree
Hide file tree
Showing 131 changed files with 3,168 additions and 2,006 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ package de.fraunhofer.aisec.cpg.analysis.fsm
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.declarations.ParameterDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration
import de.fraunhofer.aisec.cpg.graph.edge.Properties
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge
import de.fraunhofer.aisec.cpg.graph.statements.ReturnStatement
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.ConstructExpression
Expand Down Expand Up @@ -435,14 +433,12 @@ open class DFAOrderEvaluator(
val outNodes = mutableListOf<Node>()
outNodes +=
if (eliminateUnreachableCode) {
PropertyEdge.unwrap(
node.nextEOGEdges.filter { e -> e.getProperty(Properties.UNREACHABLE) != true }
)
node.nextEOGEdges.filter { e -> e.unreachable != true }.map { it.end }
} else {
node.nextEOG
}

if (outNodes.size == 1 && node.nextEOG.size == 1) {
if (outNodes.size == 1 && node.nextEOGEdges.size == 1) {
// We only have one node following this node, so we
// simply propagate the current eogPath to the next node.
outNodes[0].addEogPath(eogPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ import de.fraunhofer.aisec.cpg.analysis.ValueEvaluator
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.edge.Properties
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge
import de.fraunhofer.aisec.cpg.graph.edges.Edge
import de.fraunhofer.aisec.cpg.graph.edges.flows.EvaluationOrder
import de.fraunhofer.aisec.cpg.graph.statements.IfStatement
import de.fraunhofer.aisec.cpg.graph.statements.WhileStatement
import de.fraunhofer.aisec.cpg.helpers.*
import de.fraunhofer.aisec.cpg.passes.configuration.DependsOn

/**
* A [Pass] which uses a simple logic to determine constant values and mark unreachable code regions
* by setting the [Properties.UNREACHABLE] property of an eog-edge to true.
* by setting the [EvaluationOrder.unreachable] property to true.
*/
@DependsOn(ControlFlowSensitiveDFGPass::class)
class UnreachableEOGPass(ctx: TranslationContext) : TranslationUnitPass(ctx) {
Expand Down Expand Up @@ -68,7 +68,7 @@ class UnreachableEOGPass(ctx: TranslationContext) : TranslationUnitPass(ctx) {

for ((key, value) in finalState) {
if (value.elements == Reachability.UNREACHABLE) {
key.addProperty(Properties.UNREACHABLE, true)
(key as? EvaluationOrder)?.unreachable = true
}
}
}
Expand All @@ -90,9 +90,9 @@ class UnreachableEOGPass(ctx: TranslationContext) : TranslationUnitPass(ctx) {
* Returns the updated state and true because we always expect an update of the state.
*/
fun transfer(
currentEdge: PropertyEdge<Node>,
currentState: State<PropertyEdge<Node>, Reachability>
): State<PropertyEdge<Node>, Reachability> {
currentEdge: Edge<Node>,
currentState: State<Edge<Node>, Reachability>
): State<Edge<Node>, Reachability> {
when (val currentNode = currentEdge.end) {
is IfStatement -> {
handleIfStatement(currentEdge, currentNode, currentState)
Expand All @@ -117,22 +117,24 @@ fun transfer(
* All other cases simply copy the state which led us here.
*/
private fun handleIfStatement(
enteringEdge: PropertyEdge<Node>,
enteringEdge: Edge<Node>,
n: IfStatement,
state: State<PropertyEdge<Node>, Reachability>
state: State<Edge<Node>, Reachability>
) {
val evalResult = ValueEvaluator().evaluate(n.condition)

val (unreachableEdge, remainingEdges) =
if (evalResult is Boolean && evalResult == true) {
if (evalResult == true) {
// If the condition is always true, the "false" branch is always unreachable
Pair(
n.nextEOGEdges.firstOrNull { e -> e.getProperty(Properties.INDEX) == 1 },
n.nextEOGEdges.filter { e -> e.getProperty(Properties.INDEX) != 1 }
n.nextEOGEdges.firstOrNull { e -> e.branch == false },
n.nextEOGEdges.filter { e -> e.branch != false }
)
} else if (evalResult is Boolean && evalResult == false) {
} else if (evalResult == false) {
// If the condition is always false, the "true" branch is always unreachable
Pair(
n.nextEOGEdges.firstOrNull { e -> e.getProperty(Properties.INDEX) == 0 },
n.nextEOGEdges.filter { e -> e.getProperty(Properties.INDEX) != 0 }
n.nextEOGEdges.firstOrNull { e -> e.branch == true },
n.nextEOGEdges.filter { e -> e.branch != true }
)
} else {
Pair(null, n.nextEOGEdges)
Expand All @@ -156,9 +158,9 @@ private fun handleIfStatement(
* us here.
*/
private fun handleWhileStatement(
enteringEdge: PropertyEdge<Node>,
enteringEdge: Edge<Node>,
n: WhileStatement,
state: State<PropertyEdge<Node>, Reachability>
state: State<Edge<Node>, Reachability>
) {
/*
* Note: It does not understand that code like
Expand All @@ -173,13 +175,13 @@ private fun handleWhileStatement(
val (unreachableEdge, remainingEdges) =
if (evalResult is Boolean && evalResult == true) {
Pair(
n.nextEOGEdges.firstOrNull { e -> e.getProperty(Properties.INDEX) == 1 },
n.nextEOGEdges.filter { e -> e.getProperty(Properties.INDEX) != 1 }
n.nextEOGEdges.firstOrNull { e -> e.index == 1 },
n.nextEOGEdges.filter { e -> e.index != 1 }
)
} else if (evalResult is Boolean && evalResult == false) {
Pair(
n.nextEOGEdges.firstOrNull { e -> e.getProperty(Properties.INDEX) == 0 },
n.nextEOGEdges.filter { e -> e.getProperty(Properties.INDEX) != 0 }
n.nextEOGEdges.firstOrNull { e -> e.index == 0 },
n.nextEOGEdges.filter { e -> e.index != 0 }
)
} else {
Pair(null, n.nextEOGEdges)
Expand Down Expand Up @@ -221,7 +223,7 @@ enum class Reachability {
}

/**
* A state which actually holds a state for all [PropertyEdge]s, one only for declarations and one
* for ReturnStatements.
* A state which actually holds a state for all [Edge]s, one only for declarations and one for
* ReturnStatements.
*/
class UnreachabilityState : State<PropertyEdge<Node>, Reachability>()
class UnreachabilityState : State<Edge<Node>, Reachability>()
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ package de.fraunhofer.aisec.cpg.passes

import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.edge.Properties
import de.fraunhofer.aisec.cpg.testcases.Passes
import kotlin.test.*
import org.junit.jupiter.api.BeforeAll
Expand All @@ -51,7 +50,7 @@ class UnreachableEOGPassTest {
assertNotNull(ifStatement)

for (edge in ifStatement.nextEOGEdges) {
assertFalse(edge.getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(edge.unreachable)
}
}

Expand All @@ -66,43 +65,43 @@ class UnreachableEOGPassTest {
// Check if the then-branch is set as reachable including all the edges until reaching the
// print
val thenDecl = ifStatement.nextEOGEdges[0]
assertFalse(thenDecl.getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(thenDecl.unreachable)
assertEquals(1, thenDecl.end.nextEOGEdges.size)
// The "++"
val incOp = thenDecl.end.nextEOGEdges[0]
assertFalse(incOp.getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(incOp.unreachable)
assertEquals(1, incOp.end.nextEOGEdges.size)
// The block
val thenCompound = incOp.end.nextEOGEdges[0]
assertFalse(thenCompound.getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(thenCompound.unreachable)
assertEquals(1, thenCompound.end.nextEOGEdges.size)
// There's the outgoing EOG edge to the statement after the branching
val thenExit = thenCompound.end.nextEOGEdges[0]
assertFalse(thenExit.getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(thenExit.unreachable)

// Check if the else-branch is set as unreachable including all the edges until reaching the
// print
val elseDecl = ifStatement.nextEOGEdges[1]
assertTrue(elseDecl.getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(elseDecl.unreachable)
assertEquals(1, elseDecl.end.nextEOGEdges.size)
// The "--"
val decOp = elseDecl.end.nextEOGEdges[0]
assertTrue(decOp.getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(decOp.unreachable)
assertEquals(1, decOp.end.nextEOGEdges.size)
// The block
val elseCompound = decOp.end.nextEOGEdges[0]
assertTrue(elseCompound.getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(elseCompound.unreachable)
assertEquals(1, elseCompound.end.nextEOGEdges.size)
// There's the outgoing EOG edge to the statement after the branching
val elseExit = elseCompound.end.nextEOGEdges[0]
assertTrue(elseExit.getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(elseExit.unreachable)

// After the branching, it's reachable again. Check that we found the merge node and that we
// continue with reachable edges.
assertEquals(thenExit.end, elseExit.end)
val mergeNode = thenExit.end
assertEquals(1, mergeNode.nextEOGEdges.size)
assertFalse(mergeNode.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(mergeNode.nextEOGEdges[0].unreachable)
}

@Test
Expand All @@ -113,8 +112,8 @@ class UnreachableEOGPassTest {
val ifStatement = method.ifs.firstOrNull()
assertNotNull(ifStatement)

assertFalse(ifStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(ifStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(ifStatement.nextEOGEdges[1].unreachable)
assertTrue(ifStatement.nextEOGEdges[0].unreachable)
}

@Test
Expand All @@ -125,8 +124,8 @@ class UnreachableEOGPassTest {
val ifStatement = method.ifs.firstOrNull()
assertNotNull(ifStatement)

assertFalse(ifStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(ifStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(ifStatement.nextEOGEdges[0].unreachable)
assertTrue(ifStatement.nextEOGEdges[1].unreachable)
}

@Test
Expand All @@ -137,8 +136,8 @@ class UnreachableEOGPassTest {
val ifStatement = method.ifs.firstOrNull()
assertNotNull(ifStatement)

assertFalse(ifStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(ifStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(ifStatement.nextEOGEdges[1].unreachable)
assertTrue(ifStatement.nextEOGEdges[0].unreachable)
}

@Test
Expand All @@ -149,8 +148,8 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[0].unreachable)
assertTrue(whileStatement.nextEOGEdges[1].unreachable)
}

@Test
Expand All @@ -161,8 +160,8 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[0].unreachable)
assertFalse(whileStatement.nextEOGEdges[1].unreachable)
}

@Test
Expand All @@ -173,8 +172,8 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[0].unreachable)
assertTrue(whileStatement.nextEOGEdges[1].unreachable)
}

@Test
Expand All @@ -185,8 +184,8 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[1].unreachable)
assertTrue(whileStatement.nextEOGEdges[0].unreachable)
}

@Test
Expand All @@ -197,8 +196,8 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertTrue(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[1].unreachable)
assertTrue(whileStatement.nextEOGEdges[0].unreachable)
}

@Test
Expand All @@ -209,7 +208,7 @@ class UnreachableEOGPassTest {
val whileStatement = method.whileLoops.firstOrNull()
assertNotNull(whileStatement)

assertFalse(whileStatement.nextEOGEdges[1].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[0].getProperty(Properties.UNREACHABLE) as Boolean)
assertFalse(whileStatement.nextEOGEdges[1].unreachable)
assertFalse(whileStatement.nextEOGEdges[0].unreachable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ import de.fraunhofer.aisec.cpg.*
import de.fraunhofer.aisec.cpg.graph.Name
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.edges.ast.TemplateArguments
import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.types.*
import de.fraunhofer.aisec.cpg.graph.unknownType
import de.fraunhofer.aisec.cpg.passes.SymbolResolver
import java.io.File
import kotlin.reflect.KClass
import kotlin.reflect.full.primaryConstructor
Expand Down Expand Up @@ -322,7 +322,7 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
// matches
val source = result.source
if (this is HasTemplates && source is CallExpression) {
source.templateParameterEdges = mutableListOf()
source.templateArgumentEdges = TemplateArguments(source)
val (ok, candidates) =
this.handleTemplateFunctionCalls(
null,
Expand All @@ -336,7 +336,7 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
return Pair(candidates.toSet(), CallResolutionResult.SuccessKind.SUCCESSFUL)
}

source.templateParameterEdges = null
source.templateArgumentEdges = null
}

// If the list of viable functions is still empty at this point, the call is unresolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
package de.fraunhofer.aisec.cpg.graph

import com.fasterxml.jackson.annotation.JsonIgnore
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge
import de.fraunhofer.aisec.cpg.graph.edges.Edge
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
import de.fraunhofer.aisec.cpg.graph.types.HasType

Expand All @@ -45,4 +45,4 @@ class Assignment(

/** The holder of this assignment */
@JsonIgnore val holder: AssignmentHolder
) : PropertyEdge<Node>(value, target as Node)
) : Edge<Node>(value, target as Node)
Loading

0 comments on commit c12deb6

Please sign in to comment.