C++: Make sure the edge kind out of a throw is an 'ExceptionEdge' even if destructors are called.

This commit is contained in:
Mathias Vorreiter Pedersen
2024-04-04 20:01:52 +01:00
parent 587ae07579
commit f098b8eb82
2 changed files with 96 additions and 4 deletions

View File

@@ -814,6 +814,16 @@ newtype TTranslatedElement =
not ignoreSideEffects(expr) and
opcode = getCallSideEffectOpcode(expr)
} or
// The set of destructors to invoke after a `throw`. These need to be special
// cased because the edge kind following a throw is an `ExceptionEdge`, and
// we need to make sure that the edge kind is still an `ExceptionEdge` after
// all the destructors has run.
TTranslatedDestructorsAfterThrow(ThrowExpr throw) {
exists(DestructorCall dc |
dc = throw.getAnImplicitDestructorCall() and
not ignoreExpr(dc)
)
} or
// A precise side effect of an argument to a `Call`
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
not ignoreExpr(expr) and

View File

@@ -2833,6 +2833,68 @@ class TranslatedReuseExpr extends TranslatedNonConstantExpr {
}
}
/**
* The IR translation of the destructor calls of the parent `TranslatedThrow`.
*
* This object does not itself generate the destructor calls. Instead, its
* children provide the actual calls, and this object ensures that we correctly
* exit with an `ExceptionEdge` after executing all the destructor calls.
*/
class TranslatedDestructorsAfterThrow extends TranslatedElement, TTranslatedDestructorsAfterThrow {
ThrowExpr throw;
TranslatedDestructorsAfterThrow() { this = TTranslatedDestructorsAfterThrow(throw) }
override string toString() { result = "Destructor calls after throw: " + throw }
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
result.getExpr() = throw.getImplicitDestructorCall(id)
}
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
}
override ThrowExpr getAst() { result = throw }
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) {
result = this.getTranslatedImplicitDestructorCall(id)
}
override predicate handlesDestructorsExplicitly() { any() }
override Declaration getFunction() { result = throw.getEnclosingFunction() }
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getChild(id) |
// Transition to the next child, if any.
result = this.getChild(id + 1).getFirstInstruction(kind)
or
// And otherwise, exit this element with an exceptional edge
not exists(this.getChild(id + 1)) and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
}
override TranslatedElement getLastChild() {
result =
this.getTranslatedImplicitDestructorCall(max(int id |
exists(throw.getImplicitDestructorCall(id))
))
}
override Instruction getALastInstructionInternal() {
result = this.getLastChild().getALastInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
}
}
/**
* IR translation of a `throw` expression.
*/
@@ -2847,13 +2909,22 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = ThrowTag() and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
(
result = this.getDestructors().getFirstInstruction(kind)
or
not exists(this.getDestructors()) and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
}
override Instruction getResult() { none() }
abstract Opcode getThrowOpcode();
override predicate handlesDestructorsExplicitly() { any() }
TranslatedDestructorsAfterThrow getDestructors() { result.getAst() = expr }
}
/**
@@ -2865,6 +2936,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
final override TranslatedElement getChildInternal(int id) {
result = TranslatedVariableInitialization.super.getChildInternal(id)
or
id = max(int i | exists(TranslatedVariableInitialization.super.getChildInternal(i))) + 1 and
result = this.getDestructors()
}
final override Instruction getChildSuccessorInternal(TranslatedElement elem, EdgeKind kind) {
@@ -2930,14 +3004,22 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
class TranslatedReThrowExpr extends TranslatedThrowExpr {
override ReThrowExpr expr;
override TranslatedElement getChildInternal(int id) { none() }
override TranslatedElement getChildInternal(int id) {
id = 0 and
result = this.getDestructors()
}
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(ThrowTag()) and
kind instanceof GotoEdge
}
override Instruction getALastInstructionInternal() { result = this.getInstruction(ThrowTag()) }
override Instruction getALastInstructionInternal() {
result = this.getDestructors().getALastInstruction()
or
not this.hasAnImplicitDestructorCall() and
result = this.getInstruction(ThrowTag())
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }