Skip to content

Commit 4825774

Browse files
authored
Merge pull request github#3173 from geoffw0/opnew
C++: Support operator new and operator delete in models library
2 parents 01157e4 + ead5feb commit 4825774

File tree

9 files changed

+229
-42
lines changed

9 files changed

+229
-42
lines changed

cpp/ql/src/semmle/code/cpp/exprs/Expr.qll

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import semmle.code.cpp.Element
22
private import semmle.code.cpp.Enclosing
33
private import semmle.code.cpp.internal.ResolveClass
44
private import semmle.code.cpp.internal.AddressConstantExpression
5+
private import semmle.code.cpp.models.implementations.Allocation
56

67
/**
78
* A C/C++ expression.
@@ -804,8 +805,10 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
804805
* call the constructor of `T` but will not allocate memory.
805806
*/
806807
Expr getPlacementPointer() {
807-
isStandardPlacementNewAllocator(this.getAllocator()) and
808-
result = this.getAllocatorCall().getArgument(1)
808+
result =
809+
this
810+
.getAllocatorCall()
811+
.getArgument(this.getAllocator().(OperatorNewAllocationFunction).getPlacementArgument())
809812
}
810813
}
811814

@@ -1194,12 +1197,6 @@ private predicate convparents(Expr child, int idx, Element parent) {
11941197
)
11951198
}
11961199

1197-
private predicate isStandardPlacementNewAllocator(Function operatorNew) {
1198-
operatorNew.getName().matches("operator new%") and
1199-
operatorNew.getNumberOfParameters() = 2 and
1200-
operatorNew.getParameter(1).getType() instanceof VoidPointerType
1201-
}
1202-
12031200
// Pulled out for performance. See QL-796.
12041201
private predicate hasNoConversions(Expr e) { not e.hasConversion() }
12051202

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
343343

344344
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
345345
expr.getTarget() instanceof AllocationFunction and
346+
not exists(NewOrNewArrayExpr newExpr |
347+
// we synthesize allocator calls for `new` and `new[]`, so don't add instructions to
348+
// the existing allocator call when it exists.
349+
newExpr.getAllocatorCall() = expr
350+
) and
346351
opcode instanceof Opcode::InitializeDynamicAllocation and
347352
tag = OnlyInstructionTag() and
348353
type = getUnknownType()
@@ -358,6 +363,11 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
358363
tag = OnlyInstructionTag() and
359364
kind = gotoEdge() and
360365
expr.getTarget() instanceof AllocationFunction and
366+
not exists(NewOrNewArrayExpr newExpr |
367+
// we synthesize allocator calls for `new` and `new[]`, so don't add instructions to
368+
// the existing allocator call when it exists.
369+
newExpr.getAllocatorCall() = expr
370+
) and
361371
if exists(getChild(0))
362372
then result = getChild(0).getFirstInstruction()
363373
else result = getParent().getChildSuccessor(this)

cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,40 @@ class SizelessAllocationFunction extends AllocationFunction {
215215
}
216216
}
217217

218+
/**
219+
* An `operator new` or `operator new[]` function that may be associated with `new` or
220+
* `new[]` expressions. Note that `new` and `new[]` are not function calls, but these
221+
* functions may also be called directly.
222+
*/
223+
class OperatorNewAllocationFunction extends AllocationFunction {
224+
OperatorNewAllocationFunction() {
225+
exists(string name |
226+
hasGlobalName(name) and
227+
(
228+
// operator new(bytes, ...)
229+
name = "operator new"
230+
or
231+
// operator new[](bytes, ...)
232+
name = "operator new[]"
233+
)
234+
)
235+
}
236+
237+
override int getSizeArg() { result = 0 }
238+
239+
override predicate requiresDealloc() { not exists(getPlacementArgument()) }
240+
241+
/**
242+
* Gets the position of the placement pointer if this is a placement
243+
* `operator new` function.
244+
*/
245+
int getPlacementArgument() {
246+
getNumberOfParameters() = 2 and
247+
getParameter(1).getType() instanceof VoidPointerType and
248+
result = 1
249+
}
250+
}
251+
218252
/**
219253
* An allocation expression that is a function call, such as call to `malloc`.
220254
*/
@@ -227,7 +261,9 @@ class CallAllocationExpr extends AllocationExpr, FunctionCall {
227261
not (
228262
exists(target.getReallocPtrArg()) and
229263
getArgument(target.getSizeArg()).getValue().toInt() = 0
230-
)
264+
) and
265+
// these are modelled directly (and more accurately), avoid duplication
266+
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
231267
}
232268

233269
override Expr getSizeExpr() { result = getArgument(target.getSizeArg()) }

cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,28 @@ class StandardDeallocationFunction extends DeallocationFunction {
7979
override int getFreedArg() { result = freedArg }
8080
}
8181

82+
/**
83+
* An `operator delete` or `operator delete[]` function that may be associated
84+
* with `delete` or `delete[]` expressions. Note that `delete` and `delete[]`
85+
* are not function calls, but these functions may also be called directly.
86+
*/
87+
class OperatorDeleteDeallocationFunction extends DeallocationFunction {
88+
OperatorDeleteDeallocationFunction() {
89+
exists(string name |
90+
hasGlobalName(name) and
91+
(
92+
// operator delete(pointer, ...)
93+
name = "operator delete"
94+
or
95+
// operator delete[](pointer, ...)
96+
name = "operator delete[]"
97+
)
98+
)
99+
}
100+
101+
override int getFreedArg() { result = 0 }
102+
}
103+
82104
/**
83105
* An deallocation expression that is a function call, such as call to `free`.
84106
*/

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,9 @@ void multidimensionalNew(int x, int y) {
143143
auto p2 = new char[20][20];
144144
auto p3 = new char[x][30][30];
145145
}
146+
147+
void directOperatorCall() {
148+
void *ptr;
149+
ptr = operator new(sizeof(int));
150+
operator delete(ptr);
151+
}
Lines changed: 85 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
newExprs
2-
| allocators.cpp:49:3:49:9 | new | int | operator new(unsigned long) -> void * | 4 | 4 | |
3-
| allocators.cpp:50:3:50:15 | new | int | operator new(size_t, float) -> void * | 4 | 4 | |
4-
| allocators.cpp:51:3:51:11 | new | int | operator new(unsigned long) -> void * | 4 | 4 | |
5-
| allocators.cpp:52:3:52:14 | new | String | operator new(unsigned long) -> void * | 8 | 8 | |
6-
| allocators.cpp:53:3:53:27 | new | String | operator new(size_t, float) -> void * | 8 | 8 | |
7-
| allocators.cpp:54:3:54:17 | new | Overaligned | operator new(unsigned long, align_val_t) -> void * | 256 | 128 | aligned |
8-
| allocators.cpp:55:3:55:25 | new | Overaligned | operator new(size_t, align_val_t, float) -> void * | 256 | 128 | aligned |
9-
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator new(size_t) -> void * | 1 | 1 | |
10-
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator new(size_t, align_val_t, float) -> void * | 128 | 128 | aligned |
11-
| allocators.cpp:129:3:129:21 | new | int | operator new(size_t, void *) -> void * | 4 | 4 | |
12-
| allocators.cpp:135:3:135:26 | new | int | operator new(size_t, const nothrow_t &) -> void * | 4 | 4 | |
2+
| allocators.cpp:49:3:49:9 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
3+
| allocators.cpp:50:3:50:15 | new | int | operator new(size_t, float) -> void * | 4 | 4 | | |
4+
| allocators.cpp:51:3:51:11 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
5+
| allocators.cpp:52:3:52:14 | new | String | operator new(unsigned long) -> void * | 8 | 8 | | |
6+
| allocators.cpp:53:3:53:27 | new | String | operator new(size_t, float) -> void * | 8 | 8 | | |
7+
| allocators.cpp:54:3:54:17 | new | Overaligned | operator new(unsigned long, align_val_t) -> void * | 256 | 128 | aligned | |
8+
| allocators.cpp:55:3:55:25 | new | Overaligned | operator new(size_t, align_val_t, float) -> void * | 256 | 128 | aligned | |
9+
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator new(size_t) -> void * | 1 | 1 | | |
10+
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator new(size_t, align_val_t, float) -> void * | 128 | 128 | aligned | |
11+
| allocators.cpp:129:3:129:21 | new | int | operator new(size_t, void *) -> void * | 4 | 4 | | & ... |
12+
| allocators.cpp:135:3:135:26 | new | int | operator new(size_t, const nothrow_t &) -> void * | 4 | 4 | | |
1313
newArrayExprs
14-
| allocators.cpp:68:3:68:12 | new[] | int[] | int | operator new[](unsigned long) -> void * | 4 | 4 | | n |
15-
| allocators.cpp:69:3:69:18 | new[] | int[] | int | operator new[](size_t, float) -> void * | 4 | 4 | | n |
16-
| allocators.cpp:70:3:70:15 | new[] | String[] | String | operator new[](unsigned long) -> void * | 8 | 8 | | n |
17-
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | operator new[](unsigned long, align_val_t) -> void * | 256 | 128 | aligned | n |
18-
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | operator new[](unsigned long) -> void * | 8 | 8 | | |
19-
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | FailedInit::operator new[](size_t) -> void * | 1 | 1 | | n |
20-
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | FailedInitOveraligned::operator new[](size_t, align_val_t, float) -> void * | 128 | 128 | aligned | |
21-
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | operator new[](size_t, void *) -> void * | 4 | 4 | | |
22-
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | operator new[](size_t, const nothrow_t &) -> void * | 4 | 4 | | |
23-
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | operator new[](unsigned long) -> void * | 10 | 1 | | x |
24-
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | operator new[](unsigned long) -> void * | 20 | 1 | | |
25-
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | operator new[](unsigned long) -> void * | 900 | 1 | | x |
14+
| allocators.cpp:68:3:68:12 | new[] | int[] | int | operator new[](unsigned long) -> void * | 4 | 4 | | n | |
15+
| allocators.cpp:69:3:69:18 | new[] | int[] | int | operator new[](size_t, float) -> void * | 4 | 4 | | n | |
16+
| allocators.cpp:70:3:70:15 | new[] | String[] | String | operator new[](unsigned long) -> void * | 8 | 8 | | n | |
17+
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | operator new[](unsigned long, align_val_t) -> void * | 256 | 128 | aligned | n | |
18+
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | operator new[](unsigned long) -> void * | 8 | 8 | | | |
19+
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | FailedInit::operator new[](size_t) -> void * | 1 | 1 | | n | |
20+
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | FailedInitOveraligned::operator new[](size_t, align_val_t, float) -> void * | 128 | 128 | aligned | | |
21+
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | operator new[](size_t, void *) -> void * | 4 | 4 | | | buf |
22+
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | operator new[](size_t, const nothrow_t &) -> void * | 4 | 4 | | | |
23+
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | operator new[](unsigned long) -> void * | 10 | 1 | | x | |
24+
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | operator new[](unsigned long) -> void * | 20 | 1 | | | |
25+
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | operator new[](unsigned long) -> void * | 900 | 1 | | x | |
2626
newExprDeallocators
2727
| allocators.cpp:52:3:52:14 | new | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
2828
| allocators.cpp:53:3:53:27 | new | String | operator delete(void *, float) -> void | 8 | 8 | |
@@ -46,3 +46,65 @@ deleteArrayExprs
4646
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | operator delete[](void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
4747
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
4848
| allocators.cpp:83:3:83:23 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
49+
allocationFunctions
50+
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
51+
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
52+
| allocators.cpp:9:7:9:18 | operator new | getSizeArg = 0, requiresDealloc |
53+
| allocators.cpp:10:7:10:20 | operator new[] | getSizeArg = 0, requiresDealloc |
54+
| allocators.cpp:121:7:121:18 | operator new | getPlacementArgument = 1, getSizeArg = 0 |
55+
| allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 |
56+
| allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc |
57+
| allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc |
58+
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
59+
| file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc |
60+
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
61+
| file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc |
62+
allocationExprs
63+
| allocators.cpp:49:3:49:9 | new | getSizeBytes = 4, requiresDealloc |
64+
| allocators.cpp:50:3:50:15 | new | getSizeBytes = 4, requiresDealloc |
65+
| allocators.cpp:51:3:51:11 | new | getSizeBytes = 4, requiresDealloc |
66+
| allocators.cpp:52:3:52:14 | new | getSizeBytes = 8, requiresDealloc |
67+
| allocators.cpp:53:3:53:27 | new | getSizeBytes = 8, requiresDealloc |
68+
| allocators.cpp:54:3:54:17 | new | getSizeBytes = 256, requiresDealloc |
69+
| allocators.cpp:55:3:55:25 | new | getSizeBytes = 256, requiresDealloc |
70+
| allocators.cpp:68:3:68:12 | new[] | getSizeExpr = n, getSizeMult = 4, requiresDealloc |
71+
| allocators.cpp:69:3:69:18 | new[] | getSizeExpr = n, getSizeMult = 4, requiresDealloc |
72+
| allocators.cpp:70:3:70:15 | new[] | getSizeExpr = n, getSizeMult = 8, requiresDealloc |
73+
| allocators.cpp:71:3:71:20 | new[] | getSizeExpr = n, getSizeMult = 256, requiresDealloc |
74+
| allocators.cpp:72:3:72:16 | new[] | getSizeBytes = 80, requiresDealloc |
75+
| allocators.cpp:107:3:107:18 | new | getSizeBytes = 1, requiresDealloc |
76+
| allocators.cpp:108:3:108:19 | new[] | getSizeExpr = n, getSizeMult = 1, requiresDealloc |
77+
| allocators.cpp:109:3:109:35 | new | getSizeBytes = 128, requiresDealloc |
78+
| allocators.cpp:110:3:110:37 | new[] | getSizeBytes = 1280, requiresDealloc |
79+
| allocators.cpp:129:3:129:21 | new | getSizeBytes = 4 |
80+
| allocators.cpp:132:3:132:17 | new[] | getSizeBytes = 4 |
81+
| allocators.cpp:135:3:135:26 | new | getSizeBytes = 4, requiresDealloc |
82+
| allocators.cpp:136:3:136:26 | new[] | getSizeBytes = 8, requiresDealloc |
83+
| allocators.cpp:142:13:142:27 | new[] | getSizeExpr = x, getSizeMult = 10, requiresDealloc |
84+
| allocators.cpp:143:13:143:28 | new[] | getSizeBytes = 400, requiresDealloc |
85+
| allocators.cpp:144:13:144:31 | new[] | getSizeExpr = x, getSizeMult = 900, requiresDealloc |
86+
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
87+
deallocationFunctions
88+
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
89+
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |
90+
| allocators.cpp:13:6:13:20 | operator delete | getFreedArg = 0 |
91+
| allocators.cpp:14:6:14:22 | operator delete[] | getFreedArg = 0 |
92+
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
93+
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
94+
| file://:0:0:0:0 | operator delete | getFreedArg = 0 |
95+
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
96+
| file://:0:0:0:0 | operator delete[] | getFreedArg = 0 |
97+
deallocationExprs
98+
| allocators.cpp:59:3:59:35 | delete | getFreedExpr = 0 |
99+
| allocators.cpp:60:3:60:38 | delete | getFreedExpr = 0 |
100+
| allocators.cpp:61:3:61:44 | delete | getFreedExpr = 0 |
101+
| allocators.cpp:62:3:62:43 | delete | getFreedExpr = 0 |
102+
| allocators.cpp:63:3:63:47 | delete | getFreedExpr = 0 |
103+
| allocators.cpp:64:3:64:44 | delete | getFreedExpr = 0 |
104+
| allocators.cpp:78:3:78:37 | delete[] | getFreedExpr = 0 |
105+
| allocators.cpp:79:3:79:40 | delete[] | getFreedExpr = 0 |
106+
| allocators.cpp:80:3:80:46 | delete[] | getFreedExpr = 0 |
107+
| allocators.cpp:81:3:81:45 | delete[] | getFreedExpr = 0 |
108+
| allocators.cpp:82:3:82:49 | delete[] | getFreedExpr = 0 |
109+
| allocators.cpp:83:3:83:23 | delete[] | getFreedExpr = call to GetPointer |
110+
| allocators.cpp:150:2:150:16 | call to operator delete | getFreedExpr = ptr |

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

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import default
2+
import semmle.code.cpp.models.implementations.Allocation
23

3-
query predicate newExprs(NewExpr expr, string type, string sig, int size, int alignment, string form) {
4+
query predicate newExprs(
5+
NewExpr expr, string type, string sig, int size, int alignment, string form, string placement
6+
) {
47
exists(Function allocator, Type allocatedType |
58
expr.getAllocator() = allocator and
69
sig = allocator.getFullSignature() and
710
allocatedType = expr.getAllocatedType() and
811
type = allocatedType.toString() and
912
size = allocatedType.getSize() and
1013
alignment = allocatedType.getAlignment() and
11-
if expr.hasAlignedAllocation() then form = "aligned" else form = ""
14+
(if expr.hasAlignedAllocation() then form = "aligned" else form = "") and
15+
if exists(expr.getPlacementPointer())
16+
then placement = expr.getPlacementPointer().toString()
17+
else placement = ""
1218
)
1319
}
1420

1521
query predicate newArrayExprs(
1622
NewArrayExpr expr, string t1, string t2, string sig, int size, int alignment, string form,
17-
string extents
23+
string extents, string placement
1824
) {
1925
exists(Function allocator, Type arrayType, Type elementType |
2026
expr.getAllocator() = allocator and
@@ -26,7 +32,10 @@ query predicate newArrayExprs(
2632
size = elementType.getSize() and
2733
alignment = elementType.getAlignment() and
2834
(if expr.hasAlignedAllocation() then form = "aligned" else form = "") and
29-
extents = concat(Expr e | e = expr.getExtent() | e.toString(), ", ")
35+
extents = concat(Expr e | e = expr.getExtent() | e.toString(), ", ") and
36+
if exists(expr.getPlacementPointer())
37+
then placement = expr.getPlacementPointer().toString()
38+
else placement = ""
3039
)
3140
}
3241

@@ -101,3 +110,54 @@ query predicate deleteArrayExprs(
101110
)
102111
)
103112
}
113+
114+
string describeAllocationFunction(AllocationFunction f) {
115+
result = "getSizeArg = " + f.getSizeArg().toString()
116+
or
117+
result = "getSizeMult = " + f.getSizeMult().toString()
118+
or
119+
result = "getReallocPtrArg = " + f.getReallocPtrArg().toString()
120+
or
121+
f.requiresDealloc() and
122+
result = "requiresDealloc"
123+
or
124+
result =
125+
"getPlacementArgument = " + f.(OperatorNewAllocationFunction).getPlacementArgument().toString()
126+
}
127+
128+
query predicate allocationFunctions(AllocationFunction f, string descr) {
129+
descr = concat(describeAllocationFunction(f), ", ")
130+
}
131+
132+
string describeAllocationExpr(AllocationExpr e) {
133+
result = "getSizeExpr = " + e.getSizeExpr().toString()
134+
or
135+
result = "getSizeMult = " + e.getSizeMult().toString()
136+
or
137+
result = "getSizeBytes = " + e.getSizeBytes().toString()
138+
or
139+
result = "getReallocPtr = " + e.getReallocPtr().toString()
140+
or
141+
e.requiresDealloc() and
142+
result = "requiresDealloc"
143+
}
144+
145+
query predicate allocationExprs(AllocationExpr e, string descr) {
146+
descr = concat(describeAllocationExpr(e), ", ")
147+
}
148+
149+
string describeDeallocationFunction(DeallocationFunction f) {
150+
result = "getFreedArg = " + f.getFreedArg().toString()
151+
}
152+
153+
query predicate deallocationFunctions(DeallocationFunction f, string descr) {
154+
descr = concat(describeDeallocationFunction(f), ", ")
155+
}
156+
157+
string describeDeallocationExpr(DeallocationExpr e) {
158+
result = "getFreedExpr = " + e.getFreedExpr().toString()
159+
}
160+
161+
query predicate deallocationExprs(DeallocationExpr e, string descr) {
162+
descr = concat(describeDeallocationExpr(e), ", ")
163+
}

cpp/ql/test/library-tests/allocators/placement.expected

Lines changed: 0 additions & 2 deletions
This file was deleted.

cpp/ql/test/library-tests/allocators/placement.ql

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)