Skip to content

Commit 05819a5

Browse files
committed
C++: Print destructors for children of statements that are again statements
1 parent 332d118 commit 05819a5

File tree

5 files changed

+432
-0
lines changed

5 files changed

+432
-0
lines changed

cpp/ql/lib/semmle/code/cpp/PrintAST.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,25 @@ class StmtNode extends AstNode {
463463
}
464464
}
465465

466+
/**
467+
* A node representing a child of a `Stmt` that is itself a `Stmt`.
468+
*/
469+
class ChildStmtNode extends StmtNode {
470+
Stmt childStmt;
471+
472+
ChildStmtNode() { exists(Stmt parent | parent.getAChild() = childStmt and childStmt = ast) }
473+
474+
override BaseAstNode getChildInternal(int childIndex) {
475+
result = super.getChildInternal(childIndex)
476+
or
477+
exists(int destructorIndex |
478+
result.getAst() = childStmt.getImplicitDestructorCall(destructorIndex) and
479+
childIndex =
480+
destructorIndex + max(int index | exists(childStmt.getChild(index)) or index = 0) + 1
481+
)
482+
}
483+
}
484+
466485
/**
467486
* A node representing a `DeclStmt`.
468487
*/
@@ -674,6 +693,13 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
674693
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
675694
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
676695
(
696+
exists(Stmt s, int i | s.getChild(i) = parent |
697+
exists(int n |
698+
s.getChild(i).(Stmt).getImplicitDestructorCall(n) = child and
699+
result = "getImplicitDestructorCall(" + n + ")"
700+
)
701+
)
702+
or
677703
exists(Stmt s | s = parent |
678704
namedStmtChildPredicates(s, child, result)
679705
or

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

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22334,6 +22334,114 @@ ir.cpp:
2233422334
# 2480| Type = [Struct] B
2233522335
# 2480| ValueCategory = xvalue
2233622336
# 2481| getStmt(1): [ReturnStmt] return ...
22337+
# 2484| [TopLevelFunction] void destructor_without_block(bool)
22338+
# 2484| <params>:
22339+
# 2484| getParameter(0): [Parameter] b
22340+
# 2484| Type = [BoolType] bool
22341+
# 2485| getEntryPoint(): [BlockStmt] { ... }
22342+
# 2486| getStmt(0): [IfStmt] if (...) ...
22343+
# 2486| getCondition(): [VariableAccess] b
22344+
# 2486| Type = [BoolType] bool
22345+
# 2486| ValueCategory = prvalue(load)
22346+
# 2487| getThen(): [DeclStmt] declaration
22347+
# 2487| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
22348+
# 2487| Type = [Class] ClassWithDestructor
22349+
# 2487| getVariable().getInitializer(): [Initializer] initializer for c
22350+
# 2487| getExpr(): [ConstructorCall] call to ClassWithDestructor
22351+
# 2487| Type = [VoidType] void
22352+
# 2487| ValueCategory = prvalue
22353+
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
22354+
#-----| Type = [VoidType] void
22355+
#-----| ValueCategory = prvalue
22356+
#-----| getQualifier(): [VariableAccess] c
22357+
#-----| Type = [Class] ClassWithDestructor
22358+
#-----| ValueCategory = lvalue
22359+
# 2489| getStmt(1): [IfStmt] if (...) ...
22360+
# 2489| getCondition(): [VariableAccess] b
22361+
# 2489| Type = [BoolType] bool
22362+
# 2489| ValueCategory = prvalue(load)
22363+
# 2490| getThen(): [DeclStmt] declaration
22364+
# 2490| getDeclarationEntry(0): [VariableDeclarationEntry] definition of d
22365+
# 2490| Type = [Class] ClassWithDestructor
22366+
# 2490| getVariable().getInitializer(): [Initializer] initializer for d
22367+
# 2490| getExpr(): [ConstructorCall] call to ClassWithDestructor
22368+
# 2490| Type = [VoidType] void
22369+
# 2490| ValueCategory = prvalue
22370+
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
22371+
#-----| Type = [VoidType] void
22372+
#-----| ValueCategory = prvalue
22373+
#-----| getQualifier(): [VariableAccess] d
22374+
#-----| Type = [Class] ClassWithDestructor
22375+
#-----| ValueCategory = lvalue
22376+
# 2492| getElse(): [DeclStmt] declaration
22377+
# 2492| getDeclarationEntry(0): [VariableDeclarationEntry] definition of e
22378+
# 2492| Type = [Class] ClassWithDestructor
22379+
# 2492| getVariable().getInitializer(): [Initializer] initializer for e
22380+
# 2492| getExpr(): [ConstructorCall] call to ClassWithDestructor
22381+
# 2492| Type = [VoidType] void
22382+
# 2492| ValueCategory = prvalue
22383+
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
22384+
#-----| Type = [VoidType] void
22385+
#-----| ValueCategory = prvalue
22386+
#-----| getQualifier(): [VariableAccess] e
22387+
#-----| Type = [Class] ClassWithDestructor
22388+
#-----| ValueCategory = lvalue
22389+
# 2494| getStmt(2): [WhileStmt] while (...) ...
22390+
# 2494| getCondition(): [VariableAccess] b
22391+
# 2494| Type = [BoolType] bool
22392+
# 2494| ValueCategory = prvalue(load)
22393+
# 2495| getStmt(): [DeclStmt] declaration
22394+
# 2495| getDeclarationEntry(0): [VariableDeclarationEntry] definition of f
22395+
# 2495| Type = [Class] ClassWithDestructor
22396+
# 2495| getVariable().getInitializer(): [Initializer] initializer for f
22397+
# 2495| getExpr(): [ConstructorCall] call to ClassWithDestructor
22398+
# 2495| Type = [VoidType] void
22399+
# 2495| ValueCategory = prvalue
22400+
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
22401+
#-----| Type = [VoidType] void
22402+
#-----| ValueCategory = prvalue
22403+
#-----| getQualifier(): [VariableAccess] f
22404+
#-----| Type = [Class] ClassWithDestructor
22405+
#-----| ValueCategory = lvalue
22406+
# 2497| getStmt(3): [ForStmt] for(...;...;...) ...
22407+
# 2497| getInitialization(): [DeclStmt] declaration
22408+
# 2497| getDeclarationEntry(0): [VariableDeclarationEntry] definition of i
22409+
# 2497| Type = [IntType] int
22410+
# 2497| getVariable().getInitializer(): [Initializer] initializer for i
22411+
# 2497| getExpr(): [Literal] 0
22412+
# 2497| Type = [IntType] int
22413+
# 2497| Value = [Literal] 0
22414+
# 2497| ValueCategory = prvalue
22415+
# 2497| getCondition(): [LTExpr] ... < ...
22416+
# 2497| Type = [BoolType] bool
22417+
# 2497| ValueCategory = prvalue
22418+
# 2497| getLesserOperand(): [VariableAccess] i
22419+
# 2497| Type = [IntType] int
22420+
# 2497| ValueCategory = prvalue(load)
22421+
# 2497| getGreaterOperand(): [Literal] 42
22422+
# 2497| Type = [IntType] int
22423+
# 2497| Value = [Literal] 42
22424+
# 2497| ValueCategory = prvalue
22425+
# 2497| getUpdate(): [PrefixIncrExpr] ++ ...
22426+
# 2497| Type = [IntType] int
22427+
# 2497| ValueCategory = lvalue
22428+
# 2497| getOperand(): [VariableAccess] i
22429+
# 2497| Type = [IntType] int
22430+
# 2497| ValueCategory = lvalue
22431+
# 2498| getStmt(): [DeclStmt] declaration
22432+
# 2498| getDeclarationEntry(0): [VariableDeclarationEntry] definition of g
22433+
# 2498| Type = [Class] ClassWithDestructor
22434+
# 2498| getVariable().getInitializer(): [Initializer] initializer for g
22435+
# 2498| getExpr(): [ConstructorCall] call to ClassWithDestructor
22436+
# 2498| Type = [VoidType] void
22437+
# 2498| ValueCategory = prvalue
22438+
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
22439+
#-----| Type = [VoidType] void
22440+
#-----| ValueCategory = prvalue
22441+
#-----| getQualifier(): [VariableAccess] g
22442+
#-----| Type = [Class] ClassWithDestructor
22443+
#-----| ValueCategory = lvalue
22444+
# 2499| getStmt(4): [ReturnStmt] return ...
2233722445
perf-regression.cpp:
2233822446
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
2233922447
# 4| <params>:

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

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17805,6 +17805,159 @@ ir.cpp:
1780517805
# 2478| v2478_6(void) = AliasedUse : ~m2480_20
1780617806
# 2478| v2478_7(void) = ExitFunction :
1780717807

17808+
# 2484| void destructor_without_block(bool)
17809+
# 2484| Block 0
17810+
# 2484| v2484_1(void) = EnterFunction :
17811+
# 2484| m2484_2(unknown) = AliasedDefinition :
17812+
# 2484| m2484_3(unknown) = InitializeNonLocal :
17813+
# 2484| m2484_4(unknown) = Chi : total:m2484_2, partial:m2484_3
17814+
# 2484| r2484_5(glval<bool>) = VariableAddress[b] :
17815+
# 2484| m2484_6(bool) = InitializeParameter[b] : &:r2484_5
17816+
# 2486| r2486_1(glval<bool>) = VariableAddress[b] :
17817+
# 2486| r2486_2(bool) = Load[b] : &:r2486_1, m2484_6
17818+
# 2486| v2486_3(void) = ConditionalBranch : r2486_2
17819+
#-----| False -> Block 2
17820+
#-----| True -> Block 1
17821+
17822+
# 2487| Block 1
17823+
# 2487| r2487_1(glval<ClassWithDestructor>) = VariableAddress[c] :
17824+
# 2487| m2487_2(ClassWithDestructor) = Uninitialized[c] : &:r2487_1
17825+
# 2487| r2487_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
17826+
# 2487| v2487_4(void) = Call[ClassWithDestructor] : func:r2487_3, this:r2487_1
17827+
# 2487| m2487_5(unknown) = ^CallSideEffect : ~m2484_4
17828+
# 2487| m2487_6(unknown) = Chi : total:m2484_4, partial:m2487_5
17829+
# 2487| m2487_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2487_1
17830+
# 2487| m2487_8(ClassWithDestructor) = Chi : total:m2487_2, partial:m2487_7
17831+
#-----| r0_1(glval<ClassWithDestructor>) = VariableAddress[c] :
17832+
#-----| r0_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
17833+
#-----| v0_3(void) = Call[~ClassWithDestructor] : func:r0_2, this:r0_1
17834+
#-----| m0_4(unknown) = ^CallSideEffect : ~m2487_6
17835+
#-----| m0_5(unknown) = Chi : total:m2487_6, partial:m0_4
17836+
#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_1, m2487_8
17837+
#-----| m0_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_1
17838+
#-----| m0_8(ClassWithDestructor) = Chi : total:m2487_8, partial:m0_7
17839+
#-----| Goto -> Block 2
17840+
17841+
# 2489| Block 2
17842+
# 2489| m2489_1(unknown) = Phi : from 0:~m2484_4, from 1:~m0_5
17843+
# 2489| r2489_2(glval<bool>) = VariableAddress[b] :
17844+
# 2489| r2489_3(bool) = Load[b] : &:r2489_2, m2484_6
17845+
# 2489| v2489_4(void) = ConditionalBranch : r2489_3
17846+
#-----| False -> Block 4
17847+
#-----| True -> Block 3
17848+
17849+
# 2490| Block 3
17850+
# 2490| r2490_1(glval<ClassWithDestructor>) = VariableAddress[d] :
17851+
# 2490| m2490_2(ClassWithDestructor) = Uninitialized[d] : &:r2490_1
17852+
# 2490| r2490_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
17853+
# 2490| v2490_4(void) = Call[ClassWithDestructor] : func:r2490_3, this:r2490_1
17854+
# 2490| m2490_5(unknown) = ^CallSideEffect : ~m2489_1
17855+
# 2490| m2490_6(unknown) = Chi : total:m2489_1, partial:m2490_5
17856+
# 2490| m2490_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2490_1
17857+
# 2490| m2490_8(ClassWithDestructor) = Chi : total:m2490_2, partial:m2490_7
17858+
#-----| r0_9(glval<ClassWithDestructor>) = VariableAddress[d] :
17859+
#-----| r0_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
17860+
#-----| v0_11(void) = Call[~ClassWithDestructor] : func:r0_10, this:r0_9
17861+
#-----| m0_12(unknown) = ^CallSideEffect : ~m2490_6
17862+
#-----| m0_13(unknown) = Chi : total:m2490_6, partial:m0_12
17863+
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m2490_8
17864+
#-----| m0_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_9
17865+
#-----| m0_16(ClassWithDestructor) = Chi : total:m2490_8, partial:m0_15
17866+
#-----| Goto -> Block 5
17867+
17868+
# 2492| Block 4
17869+
# 2492| r2492_1(glval<ClassWithDestructor>) = VariableAddress[e] :
17870+
# 2492| m2492_2(ClassWithDestructor) = Uninitialized[e] : &:r2492_1
17871+
# 2492| r2492_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
17872+
# 2492| v2492_4(void) = Call[ClassWithDestructor] : func:r2492_3, this:r2492_1
17873+
# 2492| m2492_5(unknown) = ^CallSideEffect : ~m2489_1
17874+
# 2492| m2492_6(unknown) = Chi : total:m2489_1, partial:m2492_5
17875+
# 2492| m2492_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2492_1
17876+
# 2492| m2492_8(ClassWithDestructor) = Chi : total:m2492_2, partial:m2492_7
17877+
#-----| r0_17(glval<ClassWithDestructor>) = VariableAddress[e] :
17878+
#-----| r0_18(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
17879+
#-----| v0_19(void) = Call[~ClassWithDestructor] : func:r0_18, this:r0_17
17880+
#-----| m0_20(unknown) = ^CallSideEffect : ~m2492_6
17881+
#-----| m0_21(unknown) = Chi : total:m2492_6, partial:m0_20
17882+
#-----| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_17, m2492_8
17883+
#-----| m0_23(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_17
17884+
#-----| m0_24(ClassWithDestructor) = Chi : total:m2492_8, partial:m0_23
17885+
#-----| Goto -> Block 5
17886+
17887+
# 2494| Block 5
17888+
# 2494| m2494_1(unknown) = Phi : from 3:~m0_13, from 4:~m0_21, from 6:~m0_29
17889+
# 2494| r2494_2(glval<bool>) = VariableAddress[b] :
17890+
# 2494| r2494_3(bool) = Load[b] : &:r2494_2, m2484_6
17891+
# 2494| v2494_4(void) = ConditionalBranch : r2494_3
17892+
#-----| False -> Block 7
17893+
#-----| True -> Block 6
17894+
17895+
# 2495| Block 6
17896+
# 2495| r2495_1(glval<ClassWithDestructor>) = VariableAddress[f] :
17897+
# 2495| m2495_2(ClassWithDestructor) = Uninitialized[f] : &:r2495_1
17898+
# 2495| r2495_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
17899+
# 2495| v2495_4(void) = Call[ClassWithDestructor] : func:r2495_3, this:r2495_1
17900+
# 2495| m2495_5(unknown) = ^CallSideEffect : ~m2494_1
17901+
# 2495| m2495_6(unknown) = Chi : total:m2494_1, partial:m2495_5
17902+
# 2495| m2495_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2495_1
17903+
# 2495| m2495_8(ClassWithDestructor) = Chi : total:m2495_2, partial:m2495_7
17904+
#-----| r0_25(glval<ClassWithDestructor>) = VariableAddress[f] :
17905+
#-----| r0_26(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
17906+
#-----| v0_27(void) = Call[~ClassWithDestructor] : func:r0_26, this:r0_25
17907+
#-----| m0_28(unknown) = ^CallSideEffect : ~m2495_6
17908+
#-----| m0_29(unknown) = Chi : total:m2495_6, partial:m0_28
17909+
#-----| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_25, m2495_8
17910+
#-----| m0_31(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_25
17911+
#-----| m0_32(ClassWithDestructor) = Chi : total:m2495_8, partial:m0_31
17912+
#-----| Goto (back edge) -> Block 5
17913+
17914+
# 2497| Block 7
17915+
# 2497| r2497_1(glval<int>) = VariableAddress[i] :
17916+
# 2497| r2497_2(int) = Constant[0] :
17917+
# 2497| m2497_3(int) = Store[i] : &:r2497_1, r2497_2
17918+
#-----| Goto -> Block 8
17919+
17920+
# 2497| Block 8
17921+
# 2497| m2497_4(unknown) = Phi : from 7:~m2494_1, from 9:~m0_37
17922+
# 2497| m2497_5(int) = Phi : from 7:m2497_3, from 9:m2497_15
17923+
# 2497| r2497_6(glval<int>) = VariableAddress[i] :
17924+
# 2497| r2497_7(int) = Load[i] : &:r2497_6, m2497_5
17925+
# 2497| r2497_8(int) = Constant[42] :
17926+
# 2497| r2497_9(bool) = CompareLT : r2497_7, r2497_8
17927+
# 2497| v2497_10(void) = ConditionalBranch : r2497_9
17928+
#-----| False -> Block 10
17929+
#-----| True -> Block 9
17930+
17931+
# 2498| Block 9
17932+
# 2498| r2498_1(glval<ClassWithDestructor>) = VariableAddress[g] :
17933+
# 2498| m2498_2(ClassWithDestructor) = Uninitialized[g] : &:r2498_1
17934+
# 2498| r2498_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
17935+
# 2498| v2498_4(void) = Call[ClassWithDestructor] : func:r2498_3, this:r2498_1
17936+
# 2498| m2498_5(unknown) = ^CallSideEffect : ~m2497_4
17937+
# 2498| m2498_6(unknown) = Chi : total:m2497_4, partial:m2498_5
17938+
# 2498| m2498_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2498_1
17939+
# 2498| m2498_8(ClassWithDestructor) = Chi : total:m2498_2, partial:m2498_7
17940+
#-----| r0_33(glval<ClassWithDestructor>) = VariableAddress[g] :
17941+
#-----| r0_34(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
17942+
#-----| v0_35(void) = Call[~ClassWithDestructor] : func:r0_34, this:r0_33
17943+
#-----| m0_36(unknown) = ^CallSideEffect : ~m2498_6
17944+
#-----| m0_37(unknown) = Chi : total:m2498_6, partial:m0_36
17945+
#-----| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_33, m2498_8
17946+
#-----| m0_39(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_33
17947+
#-----| m0_40(ClassWithDestructor) = Chi : total:m2498_8, partial:m0_39
17948+
# 2497| r2497_11(glval<int>) = VariableAddress[i] :
17949+
# 2497| r2497_12(int) = Load[i] : &:r2497_11, m2497_5
17950+
# 2497| r2497_13(int) = Constant[1] :
17951+
# 2497| r2497_14(int) = Add : r2497_12, r2497_13
17952+
# 2497| m2497_15(int) = Store[i] : &:r2497_11, r2497_14
17953+
#-----| Goto (back edge) -> Block 8
17954+
17955+
# 2499| Block 10
17956+
# 2499| v2499_1(void) = NoOp :
17957+
# 2484| v2484_7(void) = ReturnVoid :
17958+
# 2484| v2484_8(void) = AliasedUse : ~m2497_4
17959+
# 2484| v2484_9(void) = ExitFunction :
17960+
1780817961
perf-regression.cpp:
1780917962
# 6| void Big::Big()
1781017963
# 6| Block 0

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,4 +2481,21 @@ namespace rvalue_conversion_with_destructor {
24812481
}
24822482
}
24832483

2484+
void destructor_without_block(bool b)
2485+
{
2486+
if (b)
2487+
ClassWithDestructor c;
2488+
2489+
if (b)
2490+
ClassWithDestructor d;
2491+
else
2492+
ClassWithDestructor e;
2493+
2494+
while (b)
2495+
ClassWithDestructor f;
2496+
2497+
for(int i = 0; i < 42; ++i)
2498+
ClassWithDestructor g;
2499+
}
2500+
24842501
// semmle-extractor-options: -std=c++20 --clang

0 commit comments

Comments
 (0)