Skip to content

Commit d68d2cc

Browse files
committed
C++: Fix destructor translation for handlers
1 parent 1a53b92 commit d68d2cc

File tree

4 files changed

+134
-54
lines changed

4 files changed

+134
-54
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,12 @@ newtype TTranslatedElement =
830830
not ignoreExpr(dc)
831831
)
832832
} or
833+
// The set of destructors to invoke after a handler for a `try` statement. These
834+
// need to be special cased because the destructors need to run following an
835+
// `ExceptionEdge`, but not following a `GotoEdge` edge.
836+
TTranslatedDestructorsAfterHandler(Handler handler) {
837+
exists(handler.getAnImplicitDestructorCall())
838+
} or
833839
// A precise side effect of an argument to a `Call`
834840
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
835841
not ignoreExpr(expr) and

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

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,72 @@ abstract class TranslatedHandler extends TranslatedStmt {
777777
TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) }
778778
}
779779

780+
/**
781+
* The IR translation of the destructor calls of the parent `TranslatedCatchByTypeHandler`.
782+
*
783+
* This object does not itself generate the destructor calls. Instead, its
784+
* children provide the actual calls.
785+
*/
786+
class TranslatedDestructorsAfterHandler extends TranslatedElement,
787+
TTranslatedDestructorsAfterHandler
788+
{
789+
Handler handler;
790+
791+
TranslatedDestructorsAfterHandler() { this = TTranslatedDestructorsAfterHandler(handler) }
792+
793+
override string toString() { result = "Destructor calls after handler: " + handler }
794+
795+
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
796+
result.getExpr() = handler.getImplicitDestructorCall(id)
797+
}
798+
799+
override Instruction getFirstInstruction(EdgeKind kind) {
800+
result = this.getChild(0).getFirstInstruction(kind)
801+
}
802+
803+
override Handler getAst() { result = handler }
804+
805+
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
806+
807+
override TranslatedElement getChild(int id) {
808+
result = this.getTranslatedImplicitDestructorCall(id)
809+
}
810+
811+
override predicate handlesDestructorsExplicitly() { any() }
812+
813+
override Declaration getFunction() { result = handler.getEnclosingFunction() }
814+
815+
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
816+
exists(int id | child = this.getChild(id) |
817+
// Transition to the next child, if any.
818+
result = this.getChild(id + 1).getFirstInstruction(kind)
819+
or
820+
// And otherwise, exit this element with an exceptional edge
821+
not exists(this.getChild(id + 1)) and
822+
result =
823+
getTranslatedStmt(handler)
824+
.getParent()
825+
.(TranslatedTryStmt)
826+
.getNextHandler(getTranslatedStmt(handler), kind)
827+
)
828+
}
829+
830+
override TranslatedElement getLastChild() {
831+
result =
832+
this.getTranslatedImplicitDestructorCall(max(int id |
833+
exists(handler.getImplicitDestructorCall(id))
834+
))
835+
}
836+
837+
override Instruction getALastInstructionInternal() {
838+
result = this.getLastChild().getALastInstruction()
839+
}
840+
841+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
842+
none()
843+
}
844+
}
845+
780846
/**
781847
* The IR translation of a C++ `catch` block that catches an exception with a
782848
* specific type (e.g. `catch (const std::exception&)`).
@@ -790,10 +856,14 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
790856
resultType = getVoidType()
791857
}
792858

859+
override predicate handlesDestructorsExplicitly() { any() }
860+
793861
override TranslatedElement getChildInternal(int id) {
794862
result = super.getChildInternal(id)
795863
or
796864
id = 0 and result = this.getParameter()
865+
or
866+
id = 1 and result = this.getDestructors()
797867
}
798868

799869
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
@@ -810,7 +880,9 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
810880
result = this.getParameter().getFirstInstruction(kind)
811881
or
812882
kind instanceof ExceptionEdge and
813-
result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
883+
if exists(this.getDestructors())
884+
then result = this.getDestructors().getFirstInstruction(any(GotoEdge edge))
885+
else result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
814886
)
815887
}
816888

@@ -822,6 +894,8 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
822894
private TranslatedParameter getParameter() {
823895
result = getTranslatedParameter(stmt.getParameter())
824896
}
897+
898+
private TranslatedDestructorsAfterHandler getDestructors() { result.getAst() = stmt }
825899
}
826900

827901
/**

cpp/ql/test/library-tests/ir/ir/aliased_ir.expected

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18220,44 +18220,44 @@ ir.cpp:
1822018220
# 2537| r2537_2(int) = Constant[42] :
1822118221
# 2537| m2537_3(int) = Store[#throw2537:5] : &:r2537_1, r2537_2
1822218222
# 2537| v2537_4(void) = ThrowValue : &:r2537_1, m2537_3
18223-
#-----| Exception -> Block 3
18223+
#-----| Exception -> Block 2
1822418224

1822518225
# 2534| Block 1
18226-
# 2534| m2534_5(unknown) = Phi : from 2:~m2535_6, from 4:~m2541_14
18226+
# 2534| m2534_5(unknown) = Phi : from 3:~m2541_6, from 4:~m2541_14
1822718227
# 2534| v2534_6(void) = AliasedUse : ~m2534_5
1822818228
# 2534| v2534_7(void) = ExitFunction :
1822918229

18230-
# 2534| Block 2
18231-
# 2534| v2534_8(void) = Unwind :
18232-
#-----| Goto -> Block 1
18230+
# 2539| Block 2
18231+
# 2539| v2539_1(void) = CatchByType[char] :
18232+
#-----| Exception -> Block 4
18233+
#-----| Goto -> Block 3
1823318234

1823418235
# 2539| Block 3
18235-
# 2539| v2539_1(void) = CatchByType[char] :
18236-
#-----| Exception -> Block 2
18237-
#-----| Goto -> Block 4
18236+
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
18237+
# 2539| m2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
18238+
# 2539| v2539_4(void) = NoOp :
18239+
# 2541| v2541_1(void) = NoOp :
18240+
# 2541| r2541_2(glval<ClassWithDestructor>) = VariableAddress[x] :
18241+
# 2541| r2541_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
18242+
# 2541| v2541_4(void) = Call[~ClassWithDestructor] : func:r2541_3, this:r2541_2
18243+
# 2541| m2541_5(unknown) = ^CallSideEffect : ~m2535_6
18244+
# 2541| m2541_6(unknown) = Chi : total:m2535_6, partial:m2541_5
18245+
# 2541| v2541_7(void) = ^IndirectReadSideEffect[-1] : &:r2541_2, m2535_8
18246+
# 2541| m2541_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_2
18247+
# 2541| m2541_9(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_8
18248+
# 2534| v2534_8(void) = ReturnVoid :
18249+
#-----| Goto -> Block 1
1823818250

18239-
# 2539| Block 4
18240-
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
18241-
# 2539| m2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
18242-
# 2539| v2539_4(void) = NoOp :
18243-
# 2541| r2541_1(glval<ClassWithDestructor>) = VariableAddress[x] :
18244-
# 2541| r2541_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
18245-
# 2541| v2541_3(void) = Call[~ClassWithDestructor] : func:r2541_2, this:r2541_1
18246-
# 2541| m2541_4(unknown) = ^CallSideEffect : ~m2535_6
18247-
# 2541| m2541_5(unknown) = Chi : total:m2535_6, partial:m2541_4
18248-
# 2541| v2541_6(void) = ^IndirectReadSideEffect[-1] : &:r2541_1, m2535_8
18249-
# 2541| m2541_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_1
18250-
# 2541| m2541_8(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_7
18251-
# 2541| v2541_9(void) = NoOp :
18252-
# 2541| r2541_10(glval<ClassWithDestructor>) = VariableAddress[x] :
18253-
# 2541| r2541_11(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
18254-
# 2541| v2541_12(void) = Call[~ClassWithDestructor] : func:r2541_11, this:r2541_10
18255-
# 2541| m2541_13(unknown) = ^CallSideEffect : ~m2541_5
18256-
# 2541| m2541_14(unknown) = Chi : total:m2541_5, partial:m2541_13
18257-
# 2541| v2541_15(void) = ^IndirectReadSideEffect[-1] : &:r2541_10, m2541_8
18258-
# 2541| m2541_16(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_10
18259-
# 2541| m2541_17(ClassWithDestructor) = Chi : total:m2541_8, partial:m2541_16
18260-
# 2534| v2534_9(void) = ReturnVoid :
18251+
# 2541| Block 4
18252+
# 2541| r2541_10(glval<ClassWithDestructor>) = VariableAddress[x] :
18253+
# 2541| r2541_11(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
18254+
# 2541| v2541_12(void) = Call[~ClassWithDestructor] : func:r2541_11, this:r2541_10
18255+
# 2541| m2541_13(unknown) = ^CallSideEffect : ~m2535_6
18256+
# 2541| m2541_14(unknown) = Chi : total:m2535_6, partial:m2541_13
18257+
# 2541| v2541_15(void) = ^IndirectReadSideEffect[-1] : &:r2541_10, m2535_8
18258+
# 2541| m2541_16(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_10
18259+
# 2541| m2541_17(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_16
18260+
# 2534| v2534_9(void) = Unwind :
1826118261
#-----| Goto -> Block 1
1826218262

1826318263
# 2545| void this_inconsistency(bool)

cpp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16577,39 +16577,39 @@ ir.cpp:
1657716577
# 2537| r2537_2(int) = Constant[42] :
1657816578
# 2537| mu2537_3(int) = Store[#throw2537:5] : &:r2537_1, r2537_2
1657916579
# 2537| v2537_4(void) = ThrowValue : &:r2537_1, ~m?
16580-
#-----| Exception -> Block 3
16580+
#-----| Exception -> Block 2
1658116581

1658216582
# 2534| Block 1
1658316583
# 2534| v2534_4(void) = AliasedUse : ~m?
1658416584
# 2534| v2534_5(void) = ExitFunction :
1658516585

16586-
# 2534| Block 2
16587-
# 2534| v2534_6(void) = Unwind :
16588-
#-----| Goto -> Block 1
16589-
16590-
# 2539| Block 3
16586+
# 2539| Block 2
1659116587
# 2539| v2539_1(void) = CatchByType[char] :
16592-
#-----| Exception -> Block 2
16593-
#-----| Goto -> Block 4
16588+
#-----| Exception -> Block 4
16589+
#-----| Goto -> Block 3
1659416590

16595-
# 2539| Block 4
16591+
# 2539| Block 3
1659616592
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
1659716593
# 2539| mu2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
1659816594
# 2539| v2539_4(void) = NoOp :
16599-
# 2541| r2541_1(glval<ClassWithDestructor>) = VariableAddress[x] :
16600-
# 2541| r2541_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
16601-
# 2541| v2541_3(void) = Call[~ClassWithDestructor] : func:r2541_2, this:r2541_1
16602-
# 2541| mu2541_4(unknown) = ^CallSideEffect : ~m?
16603-
# 2541| v2541_5(void) = ^IndirectReadSideEffect[-1] : &:r2541_1, ~m?
16604-
# 2541| mu2541_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_1
16605-
# 2541| v2541_7(void) = NoOp :
16606-
# 2541| r2541_8(glval<ClassWithDestructor>) = VariableAddress[x] :
16607-
# 2541| r2541_9(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
16608-
# 2541| v2541_10(void) = Call[~ClassWithDestructor] : func:r2541_9, this:r2541_8
16609-
# 2541| mu2541_11(unknown) = ^CallSideEffect : ~m?
16610-
# 2541| v2541_12(void) = ^IndirectReadSideEffect[-1] : &:r2541_8, ~m?
16611-
# 2541| mu2541_13(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_8
16612-
# 2534| v2534_7(void) = ReturnVoid :
16595+
# 2541| v2541_1(void) = NoOp :
16596+
# 2541| r2541_2(glval<ClassWithDestructor>) = VariableAddress[x] :
16597+
# 2541| r2541_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
16598+
# 2541| v2541_4(void) = Call[~ClassWithDestructor] : func:r2541_3, this:r2541_2
16599+
# 2541| mu2541_5(unknown) = ^CallSideEffect : ~m?
16600+
# 2541| v2541_6(void) = ^IndirectReadSideEffect[-1] : &:r2541_2, ~m?
16601+
# 2541| mu2541_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_2
16602+
# 2534| v2534_6(void) = ReturnVoid :
16603+
#-----| Goto -> Block 1
16604+
16605+
# 2541| Block 4
16606+
# 2541| r2541_8(glval<ClassWithDestructor>) = VariableAddress[x] :
16607+
# 2541| r2541_9(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
16608+
# 2541| v2541_10(void) = Call[~ClassWithDestructor] : func:r2541_9, this:r2541_8
16609+
# 2541| mu2541_11(unknown) = ^CallSideEffect : ~m?
16610+
# 2541| v2541_12(void) = ^IndirectReadSideEffect[-1] : &:r2541_8, ~m?
16611+
# 2541| mu2541_13(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_8
16612+
# 2534| v2534_7(void) = Unwind :
1661316613
#-----| Goto -> Block 1
1661416614

1661516615
# 2545| void this_inconsistency(bool)

0 commit comments

Comments
 (0)