Skip to content

Commit

Permalink
Merge branch 'main' into eog-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
KuechA authored Nov 6, 2024
2 parents c0baa57 + ad97725 commit e3c06a2
Show file tree
Hide file tree
Showing 19 changed files with 93 additions and 104 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 @@ -193,7 +193,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 @@ -1274,9 +1274,9 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
/**
* Calls [handleThrowOperator].
*
* See [Specification](https://fraunhofer-aisec.github.io/cpg/CPG/specs/eog/#throwstatement)
* See [Specification](https://fraunhofer-aisec.github.io/cpg/CPG/specs/eog/#throwexpression)
*/
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,9 +79,8 @@ class StatementHandler(lang: JavaLanguageFrontend?) :
stmt: Statement
): de.fraunhofer.aisec.cpg.graph.statements.Statement {
val throwStmt = stmt as ThrowStmt
val throwOperation =
this.newUnaryOperator("throw", postfix = false, prefix = true, rawNode = stmt)
throwOperation.input =
val throwOperation = newThrowExpression(rawNode = stmt)
throwOperation.exception =
frontend.expressionHandler.handle(throwStmt.expression)
as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
return throwOperation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) :
}
LLVMMetadataAsValueValueKind,
LLVMInlineAsmValueKind -> {
// TODO
return newProblemExpression(
"Metadata or ASM value kind not supported yet",
ProblemNode.ProblemType.TRANSLATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class LLVMIRLanguage : Language<LLVMIRLanguageFrontend>() {
override val frontend: KClass<out LLVMIRLanguageFrontend> = LLVMIRLanguageFrontend::class
override val compoundAssignmentOperators = setOf<String>()

// TODO: In theory, the integers can have any bitwidth from 1 to 1^32 bits. It's not known if
// TODO: In theory, the integers can have any bit-width from 1 to 1^32 bits. It's not known if
// they are interpreted as signed or unsigned.
@Transient
override val builtInTypes =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ package de.fraunhofer.aisec.cpg.frontends.llvm
import de.fraunhofer.aisec.cpg.frontends.Handler
import de.fraunhofer.aisec.cpg.frontends.TranslationException
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.*
Expand Down Expand Up @@ -175,7 +174,10 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) :
LLVMResume -> {
// Resumes propagation of an existing (in-flight) exception whose unwinding was
// interrupted with a landingpad instruction.
return newUnaryOperator("throw", postfix = false, prefix = true, rawNode = instr)
return newThrowExpression(rawNode = instr).apply {
exception =
newProblemExpression("We don't know the exception while parsing this node.")
}
}
LLVMLandingPad -> {
return handleLandingpad(instr)
Expand Down Expand Up @@ -335,10 +337,13 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) :
} else {
// "unwind to caller". As we don't know where the control flow continues,
// the best model would be to throw the exception again. Here, we only know
// that we will throw something here but we don't know what. We have to fix
// 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 =
newUnaryOperator("throw", postfix = false, prefix = true, rawNode = instr)
newThrowExpression(rawNode = instr).apply {
exception =
newProblemExpression("We don't know the exception while parsing this node.")
}
currentIfStatement?.elseStatement = throwOperation
}

Expand Down Expand Up @@ -1390,19 +1395,15 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) :
// We have multiple pairs, so we insert a declaration at the beginning of the function and
// make an assignment in each BB.
val functionName = LLVMGetValueName(bbsFunction).string
val functions =
tu.declarations.filter { d ->
(d as? FunctionDeclaration)?.name != null &&
(d as? FunctionDeclaration)?.name.toString() == functionName
}
val functions = tu.functions(functionName)
if (functions.size != 1) {
log.error(
"${functions.size} functions match the name of the one where the phi instruction is inserted. Can't handle this case."
)
throw TranslationException("Wrong number of functions for phi statement.")
}
// Create the dummy declaration at the beginning of the function body
val firstBB = (functions[0] as FunctionDeclaration).body as Block
val firstBB = functions[0].body as Block
val varName = instr.name
val type = frontend.typeOf(instr)
val declaration = newVariableDeclaration(varName, type, false, rawNode = instr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.statements.*
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
import de.fraunhofer.aisec.cpg.graph.statements.expressions.ProblemExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.UnaryOperator
import de.fraunhofer.aisec.cpg.graph.types.UnknownType
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker
import de.fraunhofer.aisec.cpg.passes.configuration.ExecuteFirst
Expand Down Expand Up @@ -162,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 @@ -172,27 +171,25 @@ 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).filter { n ->
n is UnaryOperator &&
n.operatorCode?.equals("throw") == true &&
n.input is ProblemExpression
getAllChildrenRecursively(catch).filterIsInstance<ThrowExpression>().filter { n ->
n.exception is ProblemExpression
}
if (reachableThrowNodes.isNotEmpty()) {
if (catch.parameter == null) {
Expand All @@ -212,7 +209,7 @@ class CompressLLVMPass(ctx: TranslationContext) : ComponentPass(ctx) {
)
exceptionReference.language = catch.language
exceptionReference.refersTo = catch.parameter
reachableThrowNodes.forEach { n -> (n as UnaryOperator).input = exceptionReference }
reachableThrowNodes.forEach { n -> n.exception = exceptionReference }
}
}

Expand Down
Loading

0 comments on commit e3c06a2

Please sign in to comment.