Skip to content

Commit

Permalink
Remove UnaryOperator used as throw from EOG pass and spec (#1819)
Browse files Browse the repository at this point in the history
* Remove UnaryOperator used as throw from EOG pass and spec

* Add the unspecificUnaryOperator method again for Go
  • Loading branch information
KuechA authored and lshala committed Nov 8, 2024
1 parent c631980 commit 2baddfd
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -552,46 +552,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
}

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()
handleUnspecificUnaryOperator(node)
}

/**
Expand Down Expand Up @@ -1124,15 +1085,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)

Expand Down
21 changes: 0 additions & 21 deletions docs/docs/CPG/specs/eog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -397,7 +377,6 @@ flowchart LR
parent(["ThrowExpression"]) --EOG--> catchingContext:::outer
parent -.-> child1
parent -.-> child2
```


Expand Down

0 comments on commit 2baddfd

Please sign in to comment.