From 70084be050b958ed9d72aaa529f434213773a318 Mon Sep 17 00:00:00 2001 From: Alexander Kuechler Date: Thu, 2 Nov 2023 15:34:06 +0100 Subject: [PATCH 1/2] Try some minor efficiency improvements --- .../de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt index 1c5d322f75..1d6df22a46 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt @@ -135,7 +135,7 @@ open class State : IdentityHashMap>() { // upper bound this[newNode] = newLatticeElement.lub(current) } else { - this[newNode] = newLatticeElement.duplicate() + this[newNode] = newLatticeElement } return true } @@ -147,13 +147,15 @@ open class State : IdentityHashMap>() { */ class Worklist() { /** A mapping of nodes to the state which is currently available there. */ - var globalState: MutableMap> = mutableMapOf() + var globalState = IdentityHashMap>() private set /** A list of all nodes which have already been visited. */ private val alreadySeen = IdentitySet() - constructor(globalState: MutableMap> = mutableMapOf()) : this() { + constructor( + globalState: IdentityHashMap> = IdentityHashMap>() + ) : this() { this.globalState = globalState } @@ -242,7 +244,9 @@ inline fun iterateEOG( startState: State, transformation: (K, State, Worklist) -> State ): State? { - val worklist = Worklist(mutableMapOf(Pair(startNode, startState))) + val initialState = IdentityHashMap>() + initialState[startNode] = startState + val worklist = Worklist(initialState) worklist.push(startNode, startState) while (worklist.isNotEmpty()) { @@ -273,7 +277,7 @@ inline fun , N : Any, V> iterateEOG( startState: State, transformation: (K, State, Worklist) -> State ): State? { - val globalState = mutableMapOf>() + val globalState = IdentityHashMap>() for (startEdge in startEdges) { globalState[startEdge] = startState } From 3db06c4c5126538c6b9940cfaf8c32967f226e68 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 23 Nov 2023 19:44:07 +0100 Subject: [PATCH 2/2] Using IdentityHashSet in PowersetLattice --- .../aisec/cpg/helpers/EOGWorklist.kt | 8 +++-- .../aisec/cpg/helpers/IdentitySet.kt | 13 ++++++++ .../cpg/passes/ControlFlowSensitiveDFGPass.kt | 30 +++++++++++-------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt index 1d6df22a46..ed13fa453f 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/EOGWorklist.kt @@ -55,11 +55,13 @@ abstract class LatticeElement(open val elements: T) : Comparable) : LatticeElement>(elements) { +class PowersetLattice(override val elements: IdentitySet) : + LatticeElement>(elements) { override fun lub(other: LatticeElement>) = - PowersetLattice(other.elements.union(this.elements)) + PowersetLattice(this.elements.union(other.elements)) - override fun duplicate() = PowersetLattice(this.elements.toSet()) + override fun duplicate(): LatticeElement> = + PowersetLattice(this.elements.toIdentitySet()) override fun compareTo(other: LatticeElement>): Int { return if (this.elements.containsAll(other.elements)) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/IdentitySet.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/IdentitySet.kt index da1aa76f43..6f33531cff 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/IdentitySet.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/IdentitySet.kt @@ -146,3 +146,16 @@ fun identitySetOf(vararg elements: T): IdentitySet { return set } + +infix fun IdentitySet.union(other: Iterable): IdentitySet { + val set = identitySetOf() + set += this + set += other + return set +} + +fun Collection.toIdentitySet(): IdentitySet { + val set = identitySetOf() + set += this + return set +} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlFlowSensitiveDFGPass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlFlowSensitiveDFGPass.kt index 21f5cb40c5..3d316742f7 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlFlowSensitiveDFGPass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlFlowSensitiveDFGPass.kt @@ -91,7 +91,7 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni clearFlowsOfVariableDeclarations(node) val startState = DFGPassState>() - startState.declarationsState.push(node, PowersetLattice(setOf())) + startState.declarationsState.push(node, PowersetLattice(identitySetOf())) val finalState = iterateEOG(node.nextEOGEdges, startState, ::transfer) as? DFGPassState ?: return @@ -142,7 +142,7 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni * It further determines unnecessary implicit return statement which are added by some frontends * even if every path reaching this point already contains a return statement. */ - protected fun transfer( + protected open fun transfer( currentEdge: PropertyEdge, state: State>, worklist: Worklist, Node, Set> @@ -157,19 +157,19 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni if (initializer != null) { // A variable declaration with an initializer => The initializer flows to the // declaration. This also affects tuples. We split it up later. - state.push(currentNode, PowersetLattice(setOf(initializer))) + state.push(currentNode, PowersetLattice(identitySetOf(initializer))) if (currentNode is TupleDeclaration) { // For a tuple declaration, we write the elements in this statement. We do not // really care about the tuple when using the elements subsequently. currentNode.elements.forEach { - doubleState.pushToDeclarationsState(it, PowersetLattice(setOf(it))) + doubleState.pushToDeclarationsState(it, PowersetLattice(identitySetOf(it))) } } else { // We also wrote something to this variable declaration here. doubleState.pushToDeclarationsState( currentNode, - PowersetLattice(setOf(currentNode)) + PowersetLattice(identitySetOf(currentNode)) ) } } else if (isSimpleAssignment(currentNode)) { @@ -182,7 +182,7 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni (assignment.target as? Declaration ?: (assignment.target as? Reference)?.refersTo) ?.let { doubleState.declarationsState[it] = - PowersetLattice(setOf(assignment.target as Node)) + PowersetLattice(identitySetOf(assignment.target as Node)) } } } else if (isIncOrDec(currentNode)) { @@ -194,7 +194,8 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni if (writtenDeclaration != null) { state.push(input, doubleState.declarationsState[writtenDeclaration]) - doubleState.declarationsState[writtenDeclaration] = PowersetLattice(setOf(input)) + doubleState.declarationsState[writtenDeclaration] = + PowersetLattice(identitySetOf(input)) } } else if (isCompoundAssignment(currentNode)) { // We write to the lhs, but it also serves as an input => We first get all previous @@ -209,7 +210,8 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni state.push(lhs, doubleState.declarationsState[writtenDeclaration]) // The whole current node is the place of the last update, not (only) the lhs! - doubleState.declarationsState[writtenDeclaration] = PowersetLattice(setOf(lhs)) + doubleState.declarationsState[writtenDeclaration] = + PowersetLattice(identitySetOf(lhs)) } } else if ( (currentNode as? Reference)?.access == AccessValues.READ && @@ -270,19 +272,23 @@ open class ControlFlowSensitiveDFGPass(ctx: TranslationContext) : TranslationUni iterable?.let { writtenTo?.let { - state.push(writtenTo, PowersetLattice(setOf(iterable))) + state.push(writtenTo, PowersetLattice(identitySetOf(iterable))) // Add the variable declaration (or the reference) to the list of previous // write nodes in this path - state.declarationsState[writtenDeclaration] = PowersetLattice(setOf(writtenTo)) + state.declarationsState[writtenDeclaration] = + PowersetLattice(identitySetOf(writtenTo)) } } } else if (currentNode is FunctionDeclaration) { // We have to add the parameters currentNode.parameters.forEach { - doubleState.pushToDeclarationsState(it, PowersetLattice(setOf(it))) + doubleState.pushToDeclarationsState(it, PowersetLattice(identitySetOf(it))) } } else if (currentNode is ReturnStatement) { - doubleState.returnStatements.push(currentNode, PowersetLattice(setOf(currentNode))) + doubleState.returnStatements.push( + currentNode, + PowersetLattice(identitySetOf(currentNode)) + ) } else { doubleState.declarationsState.push( currentNode,