Skip to content

Commit 7bb2b57

Browse files
authored
Merge pull request github#15964 from rdmarsh2/rdmarsh2/cpp/temp-destructors-extended
C++: IR translation for destruction of temporaries with extended lifetimes
2 parents 8711232 + 467f4e1 commit 7bb2b57

File tree

7 files changed

+204
-75
lines changed

7 files changed

+204
-75
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added destructors for temporary objects with extended lifetimes to the intermediate representation.

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,6 @@ private predicate ignoreExprAndDescendants(Expr expr) {
130130
or
131131
// suppress destructors of temporary variables until proper support is added for them.
132132
exists(Expr parent | parent.getAnImplicitDestructorCall() = expr)
133-
or
134-
exists(Stmt parent |
135-
parent.getAnImplicitDestructorCall() = expr and
136-
expr.(DestructorCall).getQualifier() instanceof ReuseExpr
137-
)
138133
}
139134

140135
/**

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,6 +2769,50 @@ class TranslatedTemporaryObjectExpr extends TranslatedNonConstantExpr,
27692769
final override Instruction getResult() { result = this.getTargetAddress() }
27702770
}
27712771

2772+
/**
2773+
* IR translation of a `ReuseExpr`.
2774+
*
2775+
* This translation produces a copy of the glvalue instruction holding the (unconverted) result
2776+
* of the reused expression. In the case where the original expression was a prvalue, the
2777+
* result will be a copy of the glvalue operand of a `TranslatedLoad`.
2778+
*/
2779+
class TranslatedReuseExpr extends TranslatedNonConstantExpr {
2780+
override ReuseExpr expr;
2781+
2782+
override Instruction getFirstInstruction(EdgeKind kind) {
2783+
result = this.getInstruction(OnlyInstructionTag()) and
2784+
kind instanceof GotoEdge
2785+
}
2786+
2787+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
2788+
opcode instanceof Opcode::CopyValue and
2789+
tag instanceof OnlyInstructionTag and
2790+
resultType = this.getResultType()
2791+
}
2792+
2793+
override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
2794+
2795+
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
2796+
tag = OnlyInstructionTag() and
2797+
kind instanceof GotoEdge and
2798+
result = this.getParent().getChildSuccessor(this, kind)
2799+
}
2800+
2801+
override TranslatedElement getChildInternal(int id) { none() }
2802+
2803+
override Instruction getALastInstructionInternal() {
2804+
result = this.getInstruction(OnlyInstructionTag())
2805+
}
2806+
2807+
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
2808+
tag = OnlyInstructionTag() and
2809+
operandTag instanceof UnaryOperandTag and
2810+
if getTranslatedExpr(expr.getReusedExpr()) instanceof TranslatedLoad
2811+
then result = getTranslatedExpr(expr.getReusedExpr()).(TranslatedLoad).getOperand().getResult()
2812+
else result = getTranslatedExpr(expr.getReusedExpr()).getResult()
2813+
}
2814+
}
2815+
27722816
/**
27732817
* IR translation of a `throw` expression.
27742818
*/

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

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -248,19 +248,9 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
248248
final override TranslatedElement getChild(int id) {
249249
result = this.getChildInternal(id)
250250
or
251-
exists(int destructorIndex, int tempDestructorCount |
251+
exists(int destructorIndex |
252252
result.(TranslatedExpr).getExpr() = stmt.getImplicitDestructorCall(destructorIndex) and
253-
id = this.getFirstDestructorCallIndex() + destructorIndex - tempDestructorCount and
254-
// suppress destructors of temporary variables until proper support is added for them.
255-
tempDestructorCount =
256-
count(DestructorCall call, int tempIndex |
257-
stmt.getImplicitDestructorCall(tempIndex) = call and
258-
tempIndex < destructorIndex and
259-
call.getQualifier() instanceof ReuseExpr
260-
|
261-
call
262-
) and
263-
not stmt.getImplicitDestructorCall(destructorIndex).getQualifier() instanceof ReuseExpr
253+
id = this.getFirstDestructorCallIndex() + destructorIndex
264254
)
265255
}
266256

@@ -271,11 +261,7 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
271261
}
272262

273263
final override predicate hasAnImplicitDestructorCall() {
274-
exists(stmt.getAnImplicitDestructorCall()) and
275-
// suppress destructors of temporary variables until proper support is added for them.
276-
exists(Expr expr | stmt.getAnImplicitDestructorCall().getQualifier() = expr |
277-
not expr instanceof ReuseExpr
278-
)
264+
exists(stmt.getAnImplicitDestructorCall())
279265
}
280266

281267
final override string toString() { result = stmt.toString() }

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

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -891,24 +891,32 @@ destructors_for_temps.cpp:
891891

892892
# 29| void temp_test3()
893893
# 29| Block 0
894-
# 29| v29_1(void) = EnterFunction :
895-
# 29| m29_2(unknown) = AliasedDefinition :
896-
# 29| m29_3(unknown) = InitializeNonLocal :
897-
# 29| m29_4(unknown) = Chi : total:m29_2, partial:m29_3
898-
# 30| r30_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs] :
899-
# 30| r30_2(glval<ClassWithDestructor2>) = VariableAddress[#temp30:38] :
900-
# 30| r30_3(glval<unknown>) = FunctionAddress[returnValue] :
901-
# 30| r30_4(ClassWithDestructor2) = Call[returnValue] : func:r30_3
902-
# 30| m30_5(unknown) = ^CallSideEffect : ~m29_4
903-
# 30| m30_6(unknown) = Chi : total:m29_4, partial:m30_5
904-
# 30| m30_7(ClassWithDestructor2) = Store[#temp30:38] : &:r30_2, r30_4
905-
# 30| r30_8(glval<ClassWithDestructor2>) = Convert : r30_2
906-
# 30| r30_9(ClassWithDestructor2 &) = CopyValue : r30_8
907-
# 30| m30_10(ClassWithDestructor2 &) = Store[rs] : &:r30_1, r30_9
908-
# 31| v31_1(void) = NoOp :
909-
# 29| v29_5(void) = ReturnVoid :
910-
# 29| v29_6(void) = AliasedUse : ~m30_6
911-
# 29| v29_7(void) = ExitFunction :
894+
# 29| v29_1(void) = EnterFunction :
895+
# 29| m29_2(unknown) = AliasedDefinition :
896+
# 29| m29_3(unknown) = InitializeNonLocal :
897+
# 29| m29_4(unknown) = Chi : total:m29_2, partial:m29_3
898+
# 30| r30_1(glval<ClassWithDestructor2 &>) = VariableAddress[rs] :
899+
# 30| r30_2(glval<ClassWithDestructor2>) = VariableAddress[#temp30:38] :
900+
# 30| r30_3(glval<unknown>) = FunctionAddress[returnValue] :
901+
# 30| r30_4(ClassWithDestructor2) = Call[returnValue] : func:r30_3
902+
# 30| m30_5(unknown) = ^CallSideEffect : ~m29_4
903+
# 30| m30_6(unknown) = Chi : total:m29_4, partial:m30_5
904+
# 30| m30_7(ClassWithDestructor2) = Store[#temp30:38] : &:r30_2, r30_4
905+
# 30| r30_8(glval<ClassWithDestructor2>) = Convert : r30_2
906+
# 30| r30_9(ClassWithDestructor2 &) = CopyValue : r30_8
907+
# 30| m30_10(ClassWithDestructor2 &) = Store[rs] : &:r30_1, r30_9
908+
# 31| v31_1(void) = NoOp :
909+
# 31| r31_2(glval<ClassWithDestructor2>) = CopyValue : r30_2
910+
# 31| r31_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
911+
# 31| v31_4(void) = Call[~ClassWithDestructor2] : func:r31_3, this:r31_2
912+
# 31| m31_5(unknown) = ^CallSideEffect : ~m30_6
913+
# 31| m31_6(unknown) = Chi : total:m30_6, partial:m31_5
914+
# 31| v31_7(void) = ^IndirectReadSideEffect[-1] : &:r31_2, m30_7
915+
# 31| m31_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r31_2
916+
# 31| m31_9(ClassWithDestructor2) = Chi : total:m30_7, partial:m31_8
917+
# 29| v29_5(void) = ReturnVoid :
918+
# 29| v29_6(void) = AliasedUse : ~m31_6
919+
# 29| v29_7(void) = ExitFunction :
912920

913921
# 33| void temp_test4()
914922
# 33| Block 0
@@ -935,16 +943,24 @@ destructors_for_temps.cpp:
935943
# 35| r35_9(ClassWithDestructor2 &) = CopyValue : r35_8
936944
# 35| m35_10(ClassWithDestructor2 &) = Store[rs2] : &:r35_1, r35_9
937945
# 36| v36_1(void) = NoOp :
938-
# 36| r36_2(glval<ClassWithDestructor2>) = VariableAddress[c] :
946+
# 36| r36_2(glval<ClassWithDestructor2>) = CopyValue : r35_2
939947
# 36| r36_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
940948
# 36| v36_4(void) = Call[~ClassWithDestructor2] : func:r36_3, this:r36_2
941949
# 36| m36_5(unknown) = ^CallSideEffect : ~m35_6
942950
# 36| m36_6(unknown) = Chi : total:m35_6, partial:m36_5
943-
# 36| v36_7(void) = ^IndirectReadSideEffect[-1] : &:r36_2, m34_8
951+
# 36| v36_7(void) = ^IndirectReadSideEffect[-1] : &:r36_2, m35_7
944952
# 36| m36_8(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r36_2
945-
# 36| m36_9(ClassWithDestructor2) = Chi : total:m34_8, partial:m36_8
953+
# 36| m36_9(ClassWithDestructor2) = Chi : total:m35_7, partial:m36_8
954+
# 36| r36_10(glval<ClassWithDestructor2>) = VariableAddress[c] :
955+
# 36| r36_11(glval<unknown>) = FunctionAddress[~ClassWithDestructor2] :
956+
# 36| v36_12(void) = Call[~ClassWithDestructor2] : func:r36_11, this:r36_10
957+
# 36| m36_13(unknown) = ^CallSideEffect : ~m36_6
958+
# 36| m36_14(unknown) = Chi : total:m36_6, partial:m36_13
959+
# 36| v36_15(void) = ^IndirectReadSideEffect[-1] : &:r36_10, m34_8
960+
# 36| m36_16(ClassWithDestructor2) = ^IndirectMayWriteSideEffect[-1] : &:r36_10
961+
# 36| m36_17(ClassWithDestructor2) = Chi : total:m34_8, partial:m36_16
946962
# 33| v33_5(void) = ReturnVoid :
947-
# 33| v33_6(void) = AliasedUse : ~m36_6
963+
# 33| v33_6(void) = AliasedUse : ~m36_14
948964
# 33| v33_7(void) = ExitFunction :
949965

950966
# 38| void temp_test5(bool)
@@ -8882,16 +8898,24 @@ ir.cpp:
88828898
# 1425| m1425_5(unknown) = Chi : total:m1423_11, partial:m1425_4
88838899
# 1425| m1425_6(String) = Store[#temp1425:5] : &:r1425_1, r1425_3
88848900
# 1426| v1426_1(void) = NoOp :
8885-
# 1426| r1426_2(glval<String>) = VariableAddress[s] :
8901+
# 1426| r1426_2(glval<String>) = CopyValue : r1416_2
88868902
# 1426| r1426_3(glval<unknown>) = FunctionAddress[~String] :
88878903
# 1426| v1426_4(void) = Call[~String] : func:r1426_3, this:r1426_2
88888904
# 1426| m1426_5(unknown) = ^CallSideEffect : ~m1425_5
88898905
# 1426| m1426_6(unknown) = Chi : total:m1425_5, partial:m1426_5
8890-
# 1426| v1426_7(void) = ^IndirectReadSideEffect[-1] : &:r1426_2, m1415_6
8906+
# 1426| v1426_7(void) = ^IndirectReadSideEffect[-1] : &:r1426_2, m1416_7
88918907
# 1426| m1426_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1426_2
8892-
# 1426| m1426_9(String) = Chi : total:m1415_6, partial:m1426_8
8908+
# 1426| m1426_9(String) = Chi : total:m1416_7, partial:m1426_8
8909+
# 1426| r1426_10(glval<String>) = VariableAddress[s] :
8910+
# 1426| r1426_11(glval<unknown>) = FunctionAddress[~String] :
8911+
# 1426| v1426_12(void) = Call[~String] : func:r1426_11, this:r1426_10
8912+
# 1426| m1426_13(unknown) = ^CallSideEffect : ~m1426_6
8913+
# 1426| m1426_14(unknown) = Chi : total:m1426_6, partial:m1426_13
8914+
# 1426| v1426_15(void) = ^IndirectReadSideEffect[-1] : &:r1426_10, m1415_6
8915+
# 1426| m1426_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1426_10
8916+
# 1426| m1426_17(String) = Chi : total:m1415_6, partial:m1426_16
88938917
# 1414| v1414_5(void) = ReturnVoid :
8894-
# 1414| v1414_6(void) = AliasedUse : ~m1426_6
8918+
# 1414| v1414_6(void) = AliasedUse : ~m1426_14
88958919
# 1414| v1414_7(void) = ExitFunction :
88968920

88978921
# 1428| void temporary_destructor_only()
@@ -8973,16 +8997,24 @@ ir.cpp:
89738997
# 1438| v1438_7(void) = ^IndirectReadSideEffect[-1] : &:r1438_2, m1431_2
89748998
# 1438| m1438_8(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1438_2
89758999
# 1438| m1438_9(destructor_only) = Chi : total:m1431_2, partial:m1438_8
8976-
# 1438| r1438_10(glval<destructor_only>) = VariableAddress[d] :
9000+
# 1438| r1438_10(glval<destructor_only>) = CopyValue : r1430_2
89779001
# 1438| r1438_11(glval<unknown>) = FunctionAddress[~destructor_only] :
89789002
# 1438| v1438_12(void) = Call[~destructor_only] : func:r1438_11, this:r1438_10
89799003
# 1438| m1438_13(unknown) = ^CallSideEffect : ~m1438_6
89809004
# 1438| m1438_14(unknown) = Chi : total:m1438_6, partial:m1438_13
8981-
# 1438| v1438_15(void) = ^IndirectReadSideEffect[-1] : &:r1438_10, m1429_6
9005+
# 1438| v1438_15(void) = ^IndirectReadSideEffect[-1] : &:r1438_10, m1430_7
89829006
# 1438| m1438_16(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1438_10
8983-
# 1438| m1438_17(destructor_only) = Chi : total:m1429_6, partial:m1438_16
9007+
# 1438| m1438_17(destructor_only) = Chi : total:m1430_7, partial:m1438_16
9008+
# 1438| r1438_18(glval<destructor_only>) = VariableAddress[d] :
9009+
# 1438| r1438_19(glval<unknown>) = FunctionAddress[~destructor_only] :
9010+
# 1438| v1438_20(void) = Call[~destructor_only] : func:r1438_19, this:r1438_18
9011+
# 1438| m1438_21(unknown) = ^CallSideEffect : ~m1438_14
9012+
# 1438| m1438_22(unknown) = Chi : total:m1438_14, partial:m1438_21
9013+
# 1438| v1438_23(void) = ^IndirectReadSideEffect[-1] : &:r1438_18, m1429_6
9014+
# 1438| m1438_24(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1438_18
9015+
# 1438| m1438_25(destructor_only) = Chi : total:m1429_6, partial:m1438_24
89849016
# 1428| v1428_5(void) = ReturnVoid :
8985-
# 1428| v1428_6(void) = AliasedUse : ~m1438_14
9017+
# 1428| v1428_6(void) = AliasedUse : ~m1438_22
89869018
# 1428| v1428_7(void) = ExitFunction :
89879019

89889020
# 1440| void temporary_copy_constructor()

0 commit comments

Comments
 (0)