Skip to content

Commit

Permalink
Replace UnaryOperator("throw") with ThrowStatement for CXX (#1815)
Browse files Browse the repository at this point in the history
* Replace UnaryOperator("throw") with ThrowStatement

* Rename ThrowStatement to ThrowExpression

* Also update node builder

* Adapt tests

* Rename test

* Update docs

* Rename methods in passes
  • Loading branch information
KuechA authored Nov 6, 2024
1 parent c516e81 commit ad97725
Show file tree
Hide file tree
Showing 17 changed files with 60 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
package de.fraunhofer.aisec.cpg.graph

import de.fraunhofer.aisec.cpg.frontends.HasShortCircuitOperators
import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend
import de.fraunhofer.aisec.cpg.graph.Node.Companion.EMPTY_NAME
import de.fraunhofer.aisec.cpg.graph.NodeBuilder.log
import de.fraunhofer.aisec.cpg.graph.edges.flows.ContextSensitiveDataflow
import de.fraunhofer.aisec.cpg.graph.statements.ThrowExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
import de.fraunhofer.aisec.cpg.graph.statements.expressions.AssignExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CollectionComprehension
Expand Down Expand Up @@ -565,6 +567,21 @@ fun MetadataProvider.newTypeExpression(
return node
}

/**
* Creates a new [ThrowExpression]. The [MetadataProvider] receiver will be used to fill different
* meta-data using [Node.applyMetadata]. Calling this extension function outside of Kotlin requires
* an appropriate [MetadataProvider], such as a [LanguageFrontend] as an additional prepended
* argument.
*/
@JvmOverloads
fun MetadataProvider.newThrowExpression(rawNode: Any? = null): ThrowExpression {
val node = ThrowExpression()
node.applyMetadata(this, EMPTY_NAME, rawNode, true)

log(node)
return node
}

/**
* Creates a new [ProblemExpression]. The [MetadataProvider] receiver will be used to fill different
* meta-data using [Node.applyMetadata]. Calling this extension function outside of Kotlin requires
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,8 @@ val Node?.forLoops: List<ForStatement>
val Node?.trys: List<TryStatement>
get() = this.allChildren()

/** Returns all [ThrowStatement] child edges in this graph, starting with this [Node]. */
val Node?.throws: List<ThrowStatement>
/** Returns all [ThrowExpression] child edges in this graph, starting with this [Node]. */
val Node?.throws: List<ThrowExpression>
get() = this.allChildren()

/** Returns all [ForEachStatement] child edges in this graph, starting with this [Node]. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,18 +356,3 @@ fun MetadataProvider.newLookupScopeStatement(
log(node)
return node
}

/**
* Creates a new [ThrowStatement]. The [MetadataProvider] receiver will be used to fill different
* meta-data using [Node.applyMetadata]. Calling this extension function outside of Kotlin requires
* an appropriate [MetadataProvider], such as a [LanguageFrontend] as an additional prepended
* argument.
*/
@JvmOverloads
fun MetadataProvider.newThrowStatement(rawNode: Any? = null): ThrowStatement {
val node = ThrowStatement()
node.applyMetadata(this, EMPTY_NAME, rawNode, true)

log(node)
return node
}
Original file line number Diff line number Diff line change
Expand Up @@ -1457,12 +1457,12 @@ infix fun Expression.assignAsExpr(rhs: AssignExpression.() -> Unit): AssignExpre
}

/**
* Creates a new [ThrowStatement] in the Fluent Node DSL and adds it to the nearest enclosing
* Creates a new [ThrowExpression] in the Fluent Node DSL and adds it to the nearest enclosing
* [StatementHolder].
*/
context(LanguageFrontend<*, *>, Holder<out Node>)
infix fun Expression.`throw`(init: (ThrowStatement.() -> Unit)?): ThrowStatement {
val node = (this@LanguageFrontend).newThrowStatement()
infix fun Expression.`throw`(init: (ThrowExpression.() -> Unit)?): ThrowExpression {
val node = (this@LanguageFrontend).newThrowExpression()
if (init != null) init(node)

val holder = this@Holder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ import java.util.Objects
import org.apache.commons.lang3.builder.ToStringBuilder
import org.neo4j.ogm.annotation.Relationship

/** Represents a `throw` or `raise` statement. */
class ThrowStatement : Statement(), ArgumentHolder {
/** Represents a `throw` or `raise` statement/expression. */
class ThrowExpression : Expression(), ArgumentHolder {

/** The exception object to be raised. */
@Relationship(value = "EXCEPTION") var exceptionEdge = astOptionalEdgeOf<Expression>()
var exception by unwrapping(ThrowStatement::exceptionEdge)
var exception by unwrapping(ThrowExpression::exceptionEdge)

/**
* Some languages (Python) can add a parent exception (or `cause`) to indicate that an exception
* was raised while handling another exception.
*/
@Relationship(value = "PARENT_EXCEPTION")
var parentExceptionEdge = astOptionalEdgeOf<Expression>()
var parentException by unwrapping(ThrowStatement::parentExceptionEdge)
var parentException by unwrapping(ThrowExpression::parentExceptionEdge)

override fun addArgument(expression: Expression) {
when {
Expand Down Expand Up @@ -75,7 +75,7 @@ class ThrowStatement : Statement(), ArgumentHolder {

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is ThrowStatement) return false
if (other !is ThrowExpression) return false
return super.equals(other) &&
exception == other.exception &&
parentException == other.parentException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class DFGPass(ctx: TranslationContext) : ComponentPass(ctx) {
is ForStatement -> handleForStatement(node)
is SwitchStatement -> handleSwitchStatement(node)
is IfStatement -> handleIfStatement(node)
is ThrowStatement -> handleThrowStatement(node)
is ThrowExpression -> handleThrowExpression(node)
// Declarations
is FieldDeclaration -> handleFieldDeclaration(node)
is FunctionDeclaration -> handleFunctionDeclaration(node, functionSummaries)
Expand Down Expand Up @@ -169,8 +169,8 @@ class DFGPass(ctx: TranslationContext) : ComponentPass(ctx) {
comprehension.predicate?.let { comprehension.prevDFG += it }
}

/** Handle a [ThrowStatement]. The exception and parent exception flow into the node. */
protected fun handleThrowStatement(node: ThrowStatement) {
/** Handle a [ThrowExpression]. The exception and parent exception flow into the node. */
protected fun handleThrowExpression(node: ThrowExpression) {
node.exception?.let { node.prevDFGEdges += it }
node.parentException?.let { node.prevDFGEdges += it }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
map[LookupScopeStatement::class.java] = {
handleLookupScopeStatement(it as LookupScopeStatement)
}
map[ThrowStatement::class.java] = { handleThrowStatement(it as ThrowStatement) }
map[ThrowExpression::class.java] = { handleThrowExpression(it as ThrowExpression) }
}

protected fun doNothing() {
Expand Down Expand Up @@ -1124,7 +1124,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
}

/** Calls [handleThrowOperator]. */
protected fun handleThrowStatement(statement: ThrowStatement) {
protected fun handleThrowExpression(statement: ThrowExpression) {
handleThrowOperator(
statement,
statement.exception?.type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import de.fraunhofer.aisec.cpg.GraphExamples.Companion.testFrontend
import de.fraunhofer.aisec.cpg.TranslationConfiguration
import de.fraunhofer.aisec.cpg.frontends.TestLanguage
import de.fraunhofer.aisec.cpg.graph.builder.*
import de.fraunhofer.aisec.cpg.graph.statements.ThrowStatement
import de.fraunhofer.aisec.cpg.graph.statements.ThrowExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.test.assertLocalName
import kotlin.test.*

class ThrowStatementTest {
class ThrowExpressionTest {
@Test
fun testThrow() {
val result =
Expand Down Expand Up @@ -69,21 +69,21 @@ class ThrowStatementTest {
assertIs<Block>(body)

val emptyThrow = body.statements.getOrNull(0)
assertIs<ThrowStatement>(emptyThrow)
assertIs<ThrowExpression>(emptyThrow)
println(emptyThrow.toString()) // This is only here to simulate a higher test coverage
assertNull(emptyThrow.exception)
assertTrue(emptyThrow.prevDFG.isEmpty())

val throwWithExc = body.statements.getOrNull(1)
assertIs<ThrowStatement>(throwWithExc)
assertIs<ThrowExpression>(throwWithExc)
println(throwWithExc.toString()) // This is only here to simulate a higher test coverage
val throwCall = throwWithExc.exception
assertIs<CallExpression>(throwCall)
assertLocalName("SomeError", throwCall)
assertEquals(setOf<Node>(throwCall), throwWithExc.prevDFG.toSet())

val throwWithExcAndParent = body.statements.getOrNull(2)
assertIs<ThrowStatement>(throwWithExcAndParent)
assertIs<ThrowExpression>(throwWithExcAndParent)
println(
throwWithExcAndParent.toString()
) // This is only here to simulate a higher test coverage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ package de.fraunhofer.aisec.cpg.graph.edges.flows
import de.fraunhofer.aisec.cpg.GraphExamples.Companion.prepareThrowDFGTest
import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.statements.ThrowStatement
import de.fraunhofer.aisec.cpg.graph.statements.ThrowExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import kotlin.collections.firstOrNull
Expand Down Expand Up @@ -118,7 +118,7 @@ class DataflowTest {
assertIs<Block>(body)

val throwStmt = body.statements.getOrNull(1)
assertIs<ThrowStatement>(throwStmt)
assertIs<ThrowExpression>(throwStmt)
assertNotNull(throwStmt.exception)
val throwCall = throwStmt.exception
assertIs<CallExpression>(throwCall)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ class ExpressionHandler(lang: CXXLanguageFrontend) :
// need to information about the parenthesis.
return input as Expression
}
IASTUnaryExpression.op_throw -> operatorCode = "throw"
IASTUnaryExpression.op_throw ->
return newThrowExpression(rawNode = ctx).apply { this.exception = input }
IASTUnaryExpression.op_typeid -> operatorCode = "typeid"
IASTUnaryExpression.op_alignOf -> operatorCode = "alignof"
IASTUnaryExpression.op_sizeofParameterPack -> operatorCode = "sizeof..."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class StatementHandler(lang: JavaLanguageFrontend?) :
stmt: Statement
): de.fraunhofer.aisec.cpg.graph.statements.Statement {
val throwStmt = stmt as ThrowStmt
val throwOperation = newThrowStatement(rawNode = stmt)
val throwOperation = newThrowExpression(rawNode = stmt)
throwOperation.exception =
frontend.expressionHandler.handle(throwStmt.expression)
as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) :
LLVMResume -> {
// Resumes propagation of an existing (in-flight) exception whose unwinding was
// interrupted with a landingpad instruction.
return newThrowStatement(rawNode = instr).apply {
return newThrowExpression(rawNode = instr).apply {
exception =
newProblemExpression("We don't know the exception while parsing this node.")
}
Expand Down Expand Up @@ -340,7 +340,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) :
// that we will throw something here, but we don't know what. We have to fix
// that later once we know in which catch-block this statement is executed.
val throwOperation =
newThrowStatement(rawNode = instr).apply {
newThrowExpression(rawNode = instr).apply {
exception =
newProblemExpression("We don't know the exception while parsing this node.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class CompressLLVMPass(ctx: TranslationContext) : ComponentPass(ctx) {
}
node.catchClauses = catchClauses

fixThrowStatementsForCatch(node.catchClauses[0])
fixThrowExpressionsForCatch(node.catchClauses[0])
}
node.catchClauses.size == 1 &&
node.catchClauses[0].body?.statements?.get(0) is Block -> {
Expand All @@ -171,24 +171,24 @@ class CompressLLVMPass(ctx: TranslationContext) : ComponentPass(ctx) {
// the compound statement the body of the catch clause.
val innerCompound = node.catchClauses[0].body?.statements?.get(0) as? Block
innerCompound?.statements?.let { node.catchClauses[0].body?.statements = it }
fixThrowStatementsForCatch(node.catchClauses[0])
fixThrowExpressionsForCatch(node.catchClauses[0])
}
node.catchClauses.isNotEmpty() -> {
for (catch in node.catchClauses) {
fixThrowStatementsForCatch(catch)
fixThrowExpressionsForCatch(catch)
}
}
}
}

/**
* Checks if a throw statement which is included in this catch block does not have a parameter.
* Those statements have been artificially added e.g. by a catchswitch and need to be filled
* Checks if a throw expression which is included in this catch block does not have a parameter.
* Those expressions have been artificially added e.g. by a catchswitch and need to be filled
* now.
*/
private fun fixThrowStatementsForCatch(catch: CatchClause) {
private fun fixThrowExpressionsForCatch(catch: CatchClause) {
val reachableThrowNodes =
getAllChildrenRecursively(catch).filterIsInstance<ThrowStatement>().filter { n ->
getAllChildrenRecursively(catch).filterIsInstance<ThrowExpression>().filter { n ->
n.exception is ProblemExpression
}
if (reachableThrowNodes.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ class LLVMIRLanguageFrontendTest {

val innerCatchThrows =
(innerTry.catchClauses[0].body?.statements?.get(1) as? IfStatement)?.elseStatement
assertIs<ThrowStatement>(innerCatchThrows)
assertIs<ThrowExpression>(innerCatchThrows)
assertNotNull(innerCatchThrows.exception)
assertRefersTo(innerCatchThrows.exception, innerTry.catchClauses[0].parameter)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ class StatementHandler(frontend: PythonLanguageFrontend) :

/**
* Translates a Python [`Raise`](https://docs.python.org/3/library/ast.html#ast.Raise) into a
* [ThrowStatement].
* [ThrowExpression].
*/
private fun handleRaise(node: Python.AST.Raise): ThrowStatement {
val ret = newThrowStatement(rawNode = node)
private fun handleRaise(node: Python.AST.Raise): ThrowExpression {
val ret = newThrowExpression(rawNode = node)
node.exc?.let { ret.exception = frontend.expressionHandler.handle(it) }
node.cause?.let { ret.parentException = frontend.expressionHandler.handle(it) }
return ret
Expand Down Expand Up @@ -204,7 +204,7 @@ class StatementHandler(frontend: PythonLanguageFrontend) :
exitCallWithSysExec.addArgument(starOp)

val ifStmt = newIfStatement().implicit()
ifStmt.thenStatement = newThrowStatement().implicit()
ifStmt.thenStatement = newThrowExpression().implicit()
val neg = newUnaryOperator("not", false, false).implicit()
neg.input = exitCallWithSysExec
ifStmt.condition = neg
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/CPG/specs/dfg.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ The data flow from the input to this node and, in case of the operatorCodes ++ a

*Dangerous: We have to ensure that the first operation is performed before the last one (if applicable)*

## ThrowStatement
## ThrowExpression

Interesting fields:

Expand All @@ -441,7 +441,7 @@ The return value flows to the whole statement.
Scheme:
```mermaid
flowchart LR
exception -- DFG --> node([ThrowStatement]);
exception -- DFG --> node([ThrowExpression]);
parentException -- DFG --> node;
exception -.- node;
parentException -.- node;
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/CPG/specs/eog.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ flowchart LR
```

## ThrowStatement
## ThrowExpression
The EOG continues at an exception catching structure or a function that does a re-throw.

Interesting fields:
Expand All @@ -394,7 +394,7 @@ flowchart LR
prev:::outer --EOG--> child1["exception"]
child1 --EOG--> child2["parentException"]
child2 --EOG-->parent
parent(["ThrowStatement"]) --EOG--> catchingContext:::outer
parent(["ThrowExpression"]) --EOG--> catchingContext:::outer
parent -.-> child1
parent -.-> child2
Expand Down

0 comments on commit ad97725

Please sign in to comment.