Skip to content

Commit f098b8e

Browse files
committed
C++: Make sure the edge kind out of a throw is an 'ExceptionEdge' even if destructors are called.
1 parent 587ae07 commit f098b8e

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,16 @@ newtype TTranslatedElement =
814814
not ignoreSideEffects(expr) and
815815
opcode = getCallSideEffectOpcode(expr)
816816
} or
817+
// The set of destructors to invoke after a `throw`. These need to be special
818+
// cased because the edge kind following a throw is an `ExceptionEdge`, and
819+
// we need to make sure that the edge kind is still an `ExceptionEdge` after
820+
// all the destructors has run.
821+
TTranslatedDestructorsAfterThrow(ThrowExpr throw) {
822+
exists(DestructorCall dc |
823+
dc = throw.getAnImplicitDestructorCall() and
824+
not ignoreExpr(dc)
825+
)
826+
} or
817827
// A precise side effect of an argument to a `Call`
818828
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
819829
not ignoreExpr(expr) and

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2833,6 +2833,68 @@ class TranslatedReuseExpr extends TranslatedNonConstantExpr {
28332833
}
28342834
}
28352835

2836+
/**
2837+
* The IR translation of the destructor calls of the parent `TranslatedThrow`.
2838+
*
2839+
* This object does not itself generate the destructor calls. Instead, its
2840+
* children provide the actual calls, and this object ensures that we correctly
2841+
* exit with an `ExceptionEdge` after executing all the destructor calls.
2842+
*/
2843+
class TranslatedDestructorsAfterThrow extends TranslatedElement, TTranslatedDestructorsAfterThrow {
2844+
ThrowExpr throw;
2845+
2846+
TranslatedDestructorsAfterThrow() { this = TTranslatedDestructorsAfterThrow(throw) }
2847+
2848+
override string toString() { result = "Destructor calls after throw: " + throw }
2849+
2850+
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
2851+
result.getExpr() = throw.getImplicitDestructorCall(id)
2852+
}
2853+
2854+
override Instruction getFirstInstruction(EdgeKind kind) {
2855+
result = this.getChild(0).getFirstInstruction(kind)
2856+
}
2857+
2858+
override ThrowExpr getAst() { result = throw }
2859+
2860+
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
2861+
2862+
override TranslatedElement getChild(int id) {
2863+
result = this.getTranslatedImplicitDestructorCall(id)
2864+
}
2865+
2866+
override predicate handlesDestructorsExplicitly() { any() }
2867+
2868+
override Declaration getFunction() { result = throw.getEnclosingFunction() }
2869+
2870+
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
2871+
exists(int id | child = this.getChild(id) |
2872+
// Transition to the next child, if any.
2873+
result = this.getChild(id + 1).getFirstInstruction(kind)
2874+
or
2875+
// And otherwise, exit this element with an exceptional edge
2876+
not exists(this.getChild(id + 1)) and
2877+
kind instanceof ExceptionEdge and
2878+
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
2879+
)
2880+
}
2881+
2882+
override TranslatedElement getLastChild() {
2883+
result =
2884+
this.getTranslatedImplicitDestructorCall(max(int id |
2885+
exists(throw.getImplicitDestructorCall(id))
2886+
))
2887+
}
2888+
2889+
override Instruction getALastInstructionInternal() {
2890+
result = this.getLastChild().getALastInstruction()
2891+
}
2892+
2893+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
2894+
none()
2895+
}
2896+
}
2897+
28362898
/**
28372899
* IR translation of a `throw` expression.
28382900
*/
@@ -2847,13 +2909,22 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
28472909

28482910
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
28492911
tag = ThrowTag() and
2850-
kind instanceof ExceptionEdge and
2851-
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
2912+
(
2913+
result = this.getDestructors().getFirstInstruction(kind)
2914+
or
2915+
not exists(this.getDestructors()) and
2916+
kind instanceof ExceptionEdge and
2917+
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
2918+
)
28522919
}
28532920

28542921
override Instruction getResult() { none() }
28552922

28562923
abstract Opcode getThrowOpcode();
2924+
2925+
override predicate handlesDestructorsExplicitly() { any() }
2926+
2927+
TranslatedDestructorsAfterThrow getDestructors() { result.getAst() = expr }
28572928
}
28582929

28592930
/**
@@ -2865,6 +2936,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
28652936

28662937
final override TranslatedElement getChildInternal(int id) {
28672938
result = TranslatedVariableInitialization.super.getChildInternal(id)
2939+
or
2940+
id = max(int i | exists(TranslatedVariableInitialization.super.getChildInternal(i))) + 1 and
2941+
result = this.getDestructors()
28682942
}
28692943

28702944
final override Instruction getChildSuccessorInternal(TranslatedElement elem, EdgeKind kind) {
@@ -2930,14 +3004,22 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
29303004
class TranslatedReThrowExpr extends TranslatedThrowExpr {
29313005
override ReThrowExpr expr;
29323006

2933-
override TranslatedElement getChildInternal(int id) { none() }
3007+
override TranslatedElement getChildInternal(int id) {
3008+
id = 0 and
3009+
result = this.getDestructors()
3010+
}
29343011

29353012
override Instruction getFirstInstruction(EdgeKind kind) {
29363013
result = this.getInstruction(ThrowTag()) and
29373014
kind instanceof GotoEdge
29383015
}
29393016

2940-
override Instruction getALastInstructionInternal() { result = this.getInstruction(ThrowTag()) }
3017+
override Instruction getALastInstructionInternal() {
3018+
result = this.getDestructors().getALastInstruction()
3019+
or
3020+
not this.hasAnImplicitDestructorCall() and
3021+
result = this.getInstruction(ThrowTag())
3022+
}
29413023

29423024
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
29433025

0 commit comments

Comments
 (0)