Skip to content

Commit 187e136

Browse files
author
Dave Bartolomeo
committed
C++: Generate IR side effects for smart pointer indirections
When inserting side effect instructions for argument indirections, we now insert side effects for smart pointers as we would for raw pointers. The address operand of the side effect instruction is the smart pointer object, which is a bit odd. However, I'd like to think through the design of a more principled solution before doing additional work. A few new tests are added to the existing IR tests. In addition, the IR tests now `#include` some of the shared STL headers. I've disabled IR dumps for functions from those headers, since they only get in the way of the test cases we intended.
1 parent f0a994a commit 187e136

File tree

10 files changed

+210
-3
lines changed

10 files changed

+210
-3
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
private import cpp
99
private import semmle.code.cpp.ir.implementation.Opcode
10+
private import semmle.code.cpp.models.interfaces.PointerWrapper
1011
private import semmle.code.cpp.models.interfaces.SideEffect
1112

1213
/**
@@ -39,7 +40,8 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
3940
exists(Type t | t = expr.getUnspecifiedType() |
4041
t instanceof ArrayType or
4142
t instanceof PointerType or
42-
t instanceof ReferenceType
43+
t instanceof ReferenceType or
44+
t instanceof PointerWrapper
4345
) and
4446
(
4547
isWrite = true and

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

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11365,6 +11365,86 @@ perf-regression.cpp:
1136511365
# 12| Type = [IntType] int
1136611366
# 12| Value = [Literal] 0
1136711367
# 12| ValueCategory = prvalue
11368+
smart_ptr.cpp:
11369+
# 8| [TopLevelFunction] void unique_ptr_arg(std::unique_ptr<int, std::default_delete<int>>)
11370+
# 8| <params>:
11371+
# 8| getParameter(0): [Parameter] up
11372+
# 8| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
11373+
# 10| [TopLevelFunction] void call_unique_ptr_arg(int*)
11374+
# 10| <params>:
11375+
# 10| getParameter(0): [Parameter] p
11376+
# 10| Type = [IntPointerType] int *
11377+
# 10| getEntryPoint(): [BlockStmt] { ... }
11378+
# 11| getStmt(0): [DeclStmt] declaration
11379+
# 11| getDeclarationEntry(0): [VariableDeclarationEntry] definition of up
11380+
# 11| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
11381+
# 11| getVariable().getInitializer(): [Initializer] initializer for up
11382+
# 11| getExpr(): [ConstructorCall] call to unique_ptr
11383+
# 11| Type = [VoidType] void
11384+
# 11| ValueCategory = prvalue
11385+
# 11| getArgument(0): [VariableAccess] p
11386+
# 11| Type = [IntPointerType] int *
11387+
# 11| ValueCategory = prvalue(load)
11388+
# 12| getStmt(1): [ExprStmt] ExprStmt
11389+
# 12| getExpr(): [FunctionCall] call to unique_ptr_arg
11390+
# 12| Type = [VoidType] void
11391+
# 12| ValueCategory = prvalue
11392+
# 12| getArgument(0): [FunctionCall] call to move
11393+
# 12| Type = [RValueReferenceType] type &&
11394+
# 12| ValueCategory = prvalue
11395+
# 12| getArgument(0): [VariableAccess] up
11396+
# 12| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
11397+
# 12| ValueCategory = lvalue
11398+
# 12| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
11399+
# 12| Type = [LValueReferenceType] unique_ptr<int, default_delete<int>> &
11400+
# 12| ValueCategory = prvalue
11401+
# 12| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
11402+
# 12| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
11403+
# 12| ValueCategory = lvalue
11404+
# 12| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
11405+
# 12| Type = [CTypedefType,NestedTypedefType] type
11406+
# 12| ValueCategory = prvalue(load)
11407+
# 13| getStmt(2): [ReturnStmt] return ...
11408+
# 15| [TopLevelFunction] void shared_ptr_arg(std::shared_ptr<float>)
11409+
# 15| <params>:
11410+
# 15| getParameter(0): [Parameter] sp
11411+
# 15| Type = [ClassTemplateInstantiation] shared_ptr<float>
11412+
# 17| [TopLevelFunction] void call_shared_ptr_arg(float*)
11413+
# 17| <params>:
11414+
# 17| getParameter(0): [Parameter] p
11415+
# 17| Type = [PointerType] float *
11416+
# 17| getEntryPoint(): [BlockStmt] { ... }
11417+
# 18| getStmt(0): [DeclStmt] declaration
11418+
# 18| getDeclarationEntry(0): [VariableDeclarationEntry] definition of sp
11419+
# 18| Type = [ClassTemplateInstantiation] shared_ptr<float>
11420+
# 18| getVariable().getInitializer(): [Initializer] initializer for sp
11421+
# 18| getExpr(): [ConstructorCall] call to shared_ptr
11422+
# 18| Type = [VoidType] void
11423+
# 18| ValueCategory = prvalue
11424+
# 18| getArgument(0): [VariableAccess] p
11425+
# 18| Type = [PointerType] float *
11426+
# 18| ValueCategory = prvalue(load)
11427+
# 19| getStmt(1): [ExprStmt] ExprStmt
11428+
# 19| getExpr(): [FunctionCall] call to shared_ptr_arg
11429+
# 19| Type = [VoidType] void
11430+
# 19| ValueCategory = prvalue
11431+
# 19| getArgument(0): [ConstructorCall] call to shared_ptr
11432+
# 19| Type = [VoidType] void
11433+
# 19| ValueCategory = prvalue
11434+
# 19| getArgument(0): [VariableAccess] sp
11435+
# 19| Type = [ClassTemplateInstantiation] shared_ptr<float>
11436+
# 19| ValueCategory = lvalue
11437+
# 19| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
11438+
# 19| Type = [LValueReferenceType] const shared_ptr<float> &
11439+
# 19| ValueCategory = prvalue
11440+
# 19| getExpr(): [CStyleCast] (const shared_ptr<float>)...
11441+
# 19| Conversion = [GlvalueConversion] glvalue conversion
11442+
# 19| Type = [SpecifiedType] const shared_ptr<float>
11443+
# 19| ValueCategory = lvalue
11444+
# 19| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
11445+
# 19| Type = [ClassTemplateInstantiation] shared_ptr<float>
11446+
# 19| ValueCategory = lvalue
11447+
# 20| getStmt(2): [ReturnStmt] return ...
1136811448
struct_init.cpp:
1136911449
# 1| [TopLevelFunction] int handler1(void*)
1137011450
# 1| <params>:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @kind graph
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.PrintAST
7+
private import PrintConfig
8+
9+
private class PrintConfig extends PrintASTConfiguration {
10+
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
11+
}

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

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
private import cpp
2+
3+
/**
4+
* Holds if the AST or IR for the specified function should be printed in the test output.
5+
*
6+
* This predicate excludes functions defined in standard headers.
7+
*/
8+
predicate shouldDumpFunction(Function func) {
9+
not func.getLocation().getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
10+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9+
| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() |
910
ambiguousSuccessors
1011
unexplainedLoop
1112
unnecessaryPhiInstruction

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7903,6 +7903,80 @@ perf-regression.cpp:
79037903
# 9| v9_6(void) = AliasedUse : ~m?
79047904
# 9| v9_7(void) = ExitFunction :
79057905

7906+
smart_ptr.cpp:
7907+
# 10| void call_unique_ptr_arg(int*)
7908+
# 10| Block 0
7909+
# 10| v10_1(void) = EnterFunction :
7910+
# 10| mu10_2(unknown) = AliasedDefinition :
7911+
# 10| mu10_3(unknown) = InitializeNonLocal :
7912+
# 10| r10_4(glval<int *>) = VariableAddress[p] :
7913+
# 10| mu10_5(int *) = InitializeParameter[p] : &:r10_4
7914+
# 10| r10_6(int *) = Load[p] : &:r10_4, ~m?
7915+
# 10| mu10_7(unknown) = InitializeIndirection[p] : &:r10_6
7916+
# 11| r11_1(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[up] :
7917+
# 11| mu11_2(unique_ptr<int, default_delete<int>>) = Uninitialized[up] : &:r11_1
7918+
# 11| r11_3(glval<unknown>) = FunctionAddress[unique_ptr] :
7919+
# 11| r11_4(glval<int *>) = VariableAddress[p] :
7920+
# 11| r11_5(int *) = Load[p] : &:r11_4, ~m?
7921+
# 11| v11_6(void) = Call[unique_ptr] : func:r11_3, this:r11_1, 0:r11_5
7922+
# 11| mu11_7(unknown) = ^CallSideEffect : ~m?
7923+
# 11| mu11_8(unique_ptr<int, default_delete<int>>) = ^IndirectMustWriteSideEffect[-1] : &:r11_1
7924+
# 12| r12_1(glval<unknown>) = FunctionAddress[unique_ptr_arg] :
7925+
# 12| r12_2(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[#temp12:20] :
7926+
# 12| r12_3(glval<unknown>) = FunctionAddress[move] :
7927+
# 12| r12_4(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[up] :
7928+
# 12| r12_5(unique_ptr<int, default_delete<int>> &) = CopyValue : r12_4
7929+
# 12| r12_6(unique_ptr<int, default_delete<int>> &&) = Call[move] : func:r12_3, 0:r12_5
7930+
# 12| r12_7(unique_ptr<int, default_delete<int>>) = Load[?] : &:r12_6, ~m?
7931+
# 12| mu12_8(unique_ptr<int, default_delete<int>>) = Store[#temp12:20] : &:r12_2, r12_7
7932+
# 12| r12_9(unique_ptr<int, default_delete<int>>) = Load[#temp12:20] : &:r12_2, ~m?
7933+
# 12| v12_10(void) = Call[unique_ptr_arg] : func:r12_1, 0:r12_9
7934+
# 12| mu12_11(unknown) = ^CallSideEffect : ~m?
7935+
# 12| v12_12(void) = ^BufferReadSideEffect[0] : &:r12_9, ~m?
7936+
# 13| v13_1(void) = NoOp :
7937+
# 10| v10_8(void) = ReturnIndirection[p] : &:r10_6, ~m?
7938+
# 10| v10_9(void) = ReturnVoid :
7939+
# 10| v10_10(void) = AliasedUse : ~m?
7940+
# 10| v10_11(void) = ExitFunction :
7941+
7942+
# 17| void call_shared_ptr_arg(float*)
7943+
# 17| Block 0
7944+
# 17| v17_1(void) = EnterFunction :
7945+
# 17| mu17_2(unknown) = AliasedDefinition :
7946+
# 17| mu17_3(unknown) = InitializeNonLocal :
7947+
# 17| r17_4(glval<float *>) = VariableAddress[p] :
7948+
# 17| mu17_5(float *) = InitializeParameter[p] : &:r17_4
7949+
# 17| r17_6(float *) = Load[p] : &:r17_4, ~m?
7950+
# 17| mu17_7(unknown) = InitializeIndirection[p] : &:r17_6
7951+
# 18| r18_1(glval<shared_ptr<float>>) = VariableAddress[sp] :
7952+
# 18| mu18_2(shared_ptr<float>) = Uninitialized[sp] : &:r18_1
7953+
# 18| r18_3(glval<unknown>) = FunctionAddress[shared_ptr] :
7954+
# 18| r18_4(glval<float *>) = VariableAddress[p] :
7955+
# 18| r18_5(float *) = Load[p] : &:r18_4, ~m?
7956+
# 18| v18_6(void) = Call[shared_ptr] : func:r18_3, this:r18_1, 0:r18_5
7957+
# 18| mu18_7(unknown) = ^CallSideEffect : ~m?
7958+
# 18| mu18_8(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r18_1
7959+
# 19| r19_1(glval<unknown>) = FunctionAddress[shared_ptr_arg] :
7960+
# 19| r19_2(glval<shared_ptr<float>>) = VariableAddress[#temp19:20] :
7961+
# 19| mu19_3(shared_ptr<float>) = Uninitialized[#temp19:20] : &:r19_2
7962+
# 19| r19_4(glval<unknown>) = FunctionAddress[shared_ptr] :
7963+
# 19| r19_5(glval<shared_ptr<float>>) = VariableAddress[sp] :
7964+
# 19| r19_6(glval<shared_ptr<float>>) = Convert : r19_5
7965+
# 19| r19_7(shared_ptr<float> &) = CopyValue : r19_6
7966+
# 19| v19_8(void) = Call[shared_ptr] : func:r19_4, this:r19_2, 0:r19_7
7967+
# 19| mu19_9(unknown) = ^CallSideEffect : ~m?
7968+
# 19| mu19_10(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r19_2
7969+
# 19| v19_11(void) = ^IndirectReadSideEffect[0] : &:r19_7, ~m?
7970+
# 19| r19_12(shared_ptr<float>) = Load[#temp19:20] : &:r19_2, ~m?
7971+
# 19| v19_13(void) = Call[shared_ptr_arg] : func:r19_1, 0:r19_12
7972+
# 19| mu19_14(unknown) = ^CallSideEffect : ~m?
7973+
# 19| v19_15(void) = ^BufferReadSideEffect[0] : &:r19_12, ~m?
7974+
# 20| v20_1(void) = NoOp :
7975+
# 17| v17_8(void) = ReturnIndirection[p] : &:r17_6, ~m?
7976+
# 17| v17_9(void) = ReturnVoid :
7977+
# 17| v17_10(void) = AliasedUse : ~m?
7978+
# 17| v17_11(void) = ExitFunction :
7979+
79067980
struct_init.cpp:
79077981
# 16| void let_info_escape(Info*)
79087982
# 16| Block 0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @kind graph
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.ir.implementation.raw.PrintIR
7+
private import PrintConfig
8+
9+
private class PrintConfig extends PrintIRConfiguration {
10+
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
11+
}

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

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "../../../include/memory.h"
2+
#include "../../../include/utility.h"
3+
4+
using std::move;
5+
using std::shared_ptr;
6+
using std::unique_ptr;
7+
8+
void unique_ptr_arg(unique_ptr<int> up);
9+
10+
void call_unique_ptr_arg(int* p) {
11+
unique_ptr<int> up(p);
12+
unique_ptr_arg(move(up));
13+
}
14+
15+
void shared_ptr_arg(shared_ptr<float> sp);
16+
17+
void call_shared_ptr_arg(float* p) {
18+
shared_ptr<float> sp(p);
19+
shared_ptr_arg(sp);
20+
}

0 commit comments

Comments
 (0)