From 58f373ad5faac033fe0324f2d49f35e1fa384e42 Mon Sep 17 00:00:00 2001 From: Alexander Kuechler Date: Wed, 6 Nov 2024 09:33:25 +0100 Subject: [PATCH 1/2] Remove UnaryOperator used as throw from EOG pass and spec --- .../cpg/passes/EvaluationOrderGraphPass.kt | 92 +++++++++---------- docs/docs/CPG/specs/eog.md | 21 ----- 2 files changed, 43 insertions(+), 70 deletions(-) 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 3c0bc5bb98..522763bf97 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 @@ -551,56 +551,13 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa attachToEOG(node) } - protected fun handleUnaryOperator(node: UnaryOperator) { - // TODO(oxisto): These operator codes are highly language specific and might be more suited - // to be handled differently (see https://github.com/Fraunhofer-AISEC/cpg/issues/1161) - if (node.operatorCode == "throw") { - handleThrowOperator(node, node.input.type, node.input) - } else { - handleUnspecificUnaryOperator(node) - } - } - - /** - * Generates the EOG for a [node] which represents a statement/expression which throws an - * exception. Since some languages may accept different inputs to a throw statement (typically - * 1, sometimes 2, 0 is also possible), we have collect these in [inputs]. The input which is - * evaluated first, must be the first item in the vararg! Any `null` object in `inputs` will be - * filtered. We connect the throw statement internally, i.e., the inputs are evaluated from - * index 0 to n and then the whole node is evaluated. - */ - protected fun handleThrowOperator(node: Node, throwType: Type?, vararg inputs: Expression?) { - inputs.filterNotNull().forEach { handleEOG(it) } - attachToEOG(node) - - if (throwType != null) { - // Here, we identify the encapsulating ast node that can handle or relay a throw - val handlingOrRelayingParent = - node.firstParentOrNull { parent -> - parent is TryStatement || parent is FunctionDeclaration - } - if (handlingOrRelayingParent != null) { - val throwByTypeMap = - nodesToInternalThrows.getOrPut(handlingOrRelayingParent) { mutableMapOf() } - val throwEOGExits = throwByTypeMap.getOrPut(throwType) { mutableListOf() } - throwEOGExits.addAll(currentPredecessors.toMutableList()) - } else { - LOGGER.error( - "Cannot attach throw to a parent node, throw is neither in a try statement nor in a relaying function." - ) - } - } - // After a throw, the eog is not progressing in the following ast subtrees - currentPredecessors.clear() - } - /** * This function handles all regular unary operators that do not receive any special handling * (such as [handleThrowOperator]). This gives language frontends a chance to override this * function using [ReplacePass], handle specific operators on their own and delegate the rest to * this function. */ - protected open fun handleUnspecificUnaryOperator(node: UnaryOperator) { + protected fun handleUnaryOperator(node: UnaryOperator) { val input = node.input handleEOG(input) @@ -1124,15 +1081,52 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa } /** Calls [handleThrowOperator]. */ - protected fun handleThrowExpression(statement: ThrowExpression) { + protected fun handleThrowExpression(throwExpression: ThrowExpression) { handleThrowOperator( - statement, - statement.exception?.type, - statement.exception, - statement.parentException + throwExpression, + throwExpression.exception?.type, + throwExpression.exception, + throwExpression.parentException ) } + /** + * Generates the EOG for a [throwExpression] which represents a statement/expression which + * throws an exception. Since some languages may accept different inputs to a throw statement + * (typically 1, sometimes 2, 0 is also possible), we have collect these in [inputs]. The input + * which is evaluated first, must be the first item in the vararg! Any `null` object in `inputs` + * will be filtered. We connect the throw statement internally, i.e., the inputs are evaluated + * from index 0 to n and then the whole node is evaluated. + */ + protected fun handleThrowOperator( + throwExpression: Node, + throwType: Type?, + vararg inputs: Expression? + ) { + inputs.filterNotNull().forEach { handleEOG(it) } + attachToEOG(throwExpression) + + if (throwType != null) { + // Here, we identify the encapsulating ast node that can handle or relay a throw + val handlingOrRelayingParent = + throwExpression.firstParentOrNull { parent -> + parent is TryStatement || parent is FunctionDeclaration + } + if (handlingOrRelayingParent != null) { + val throwByTypeMap = + nodesToInternalThrows.getOrPut(handlingOrRelayingParent) { mutableMapOf() } + val throwEOGExits = throwByTypeMap.getOrPut(throwType) { mutableListOf() } + throwEOGExits.addAll(currentPredecessors.toMutableList()) + } else { + LOGGER.error( + "Cannot attach throw to a parent node, throw is neither in a try statement nor in a relaying function." + ) + } + } + // After a throw, the eog is not progressing in the following ast subtrees + currentPredecessors.clear() + } + companion object { protected val LOGGER = LoggerFactory.getLogger(EvaluationOrderGraphPass::class.java) diff --git a/docs/docs/CPG/specs/eog.md b/docs/docs/CPG/specs/eog.md index d9780da824..488189cde8 100644 --- a/docs/docs/CPG/specs/eog.md +++ b/docs/docs/CPG/specs/eog.md @@ -357,26 +357,6 @@ flowchart LR child --EOG-->parent parent(["UnaryOperator"]) --EOG--> next:::outer parent -."statements(n)".-> child - -``` - - -### UnaryOperator for exception throws -Throwing of exceptions is modelled as unary operation. The EOG continues at an exception catching structure or a function that does a re-throw. - -Interesting fields: - -* `input: Expression`: Exception to be thrown for exception handling. - -Scheme: -```mermaid -flowchart LR - classDef outer fill:#fff,stroke:#ddd,stroke-dasharray:5 5; - prev:::outer --EOG--> child["input"] - child --EOG-->parent - parent(["throw"]) --EOG--> catchingContext:::outer - parent -."statements(n)".-> child - ``` ## ThrowExpression @@ -397,7 +377,6 @@ flowchart LR parent(["ThrowExpression"]) --EOG--> catchingContext:::outer parent -.-> child1 parent -.-> child2 - ``` From 49dcc8dba76cb04dcd8779aa09ab8dba09cf72eb Mon Sep 17 00:00:00 2001 From: Alexander Kuechler Date: Wed, 6 Nov 2024 10:11:08 +0100 Subject: [PATCH 2/2] Add the unspecificUnaryOperator method again for Go --- .../fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 522763bf97..f1a5da1377 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 @@ -551,13 +551,17 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa attachToEOG(node) } + protected fun handleUnaryOperator(node: UnaryOperator) { + handleUnspecificUnaryOperator(node) + } + /** * This function handles all regular unary operators that do not receive any special handling * (such as [handleThrowOperator]). This gives language frontends a chance to override this * function using [ReplacePass], handle specific operators on their own and delegate the rest to * this function. */ - protected fun handleUnaryOperator(node: UnaryOperator) { + protected open fun handleUnspecificUnaryOperator(node: UnaryOperator) { val input = node.input handleEOG(input)