Skip to content

Commit a8e1912

Browse files
committed
Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams
Merge IR SSA test additions
2 parents fd915bb + 604731b commit a8e1912

File tree

37 files changed

+1503
-413
lines changed

37 files changed

+1503
-413
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: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,44 @@ abstract class TranslatedCall extends TranslatedExpr {
206206

207207
predicate hasPreciseSideEffect() { exists(getSideEffects()) }
208208

209-
TranslatedSideEffects getSideEffects() { result.getCall() = expr }
209+
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
210+
}
211+
212+
abstract class TranslatedSideEffects extends TranslatedElement {
213+
abstract Expr getExpr();
214+
215+
final override Locatable getAST() { result = getExpr() }
216+
217+
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
218+
219+
override TranslatedElement getChild(int i) {
220+
result =
221+
rank[i + 1](TranslatedSideEffect tse, int isWrite, int index |
222+
(
223+
tse.getCall() = getExpr() and
224+
tse.getArgumentIndex() = index and
225+
if tse.isWrite() then isWrite = 1 else isWrite = 0
226+
)
227+
|
228+
tse order by isWrite, index
229+
)
230+
}
231+
232+
final override Instruction getChildSuccessor(TranslatedElement te) {
233+
exists(int i |
234+
getChild(i) = te and
235+
if exists(getChild(i + 1))
236+
then result = getChild(i + 1).getFirstInstruction()
237+
else result = getParent().getChildSuccessor(this)
238+
)
239+
}
240+
241+
/**
242+
* Gets the `TranslatedFunction` containing this expression.
243+
*/
244+
final TranslatedFunction getEnclosingFunction() {
245+
result = getTranslatedFunction(getExpr().getEnclosingFunction())
246+
}
210247
}
211248

212249
/**
@@ -308,56 +345,27 @@ class TranslatedStructorCall extends TranslatedFunctionCall {
308345
override predicate hasQualifier() { any() }
309346
}
310347

311-
class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
312-
Call expr;
313-
314-
TranslatedSideEffects() { this = TTranslatedSideEffects(expr) }
348+
class TranslatedAllocationSideEffects extends TranslatedSideEffects,
349+
TTranslatedAllocationSideEffects {
350+
AllocationExpr expr;
315351

316-
override string toString() { result = "(side effects for " + expr.toString() + ")" }
352+
TranslatedAllocationSideEffects() { this = TTranslatedAllocationSideEffects(expr) }
317353

318-
override Locatable getAST() { result = expr }
354+
final override AllocationExpr getExpr() { result = expr }
319355

320-
Call getCall() { result = expr }
356+
override string toString() { result = "(allocation side effects for " + expr.toString() + ")" }
321357

322-
override TranslatedElement getChild(int i) {
323-
result =
324-
rank[i + 1](TranslatedSideEffect tse, int isWrite, int index |
325-
(
326-
tse.getCall() = getCall() and
327-
tse.getArgumentIndex() = index and
328-
if tse.isWrite() then isWrite = 1 else isWrite = 0
329-
)
330-
|
331-
tse order by isWrite, index
332-
)
333-
}
334-
335-
override Instruction getChildSuccessor(TranslatedElement te) {
336-
exists(int i |
337-
getChild(i) = te and
338-
if exists(getChild(i + 1))
339-
then result = getChild(i + 1).getFirstInstruction()
340-
else result = getParent().getChildSuccessor(this)
341-
)
342-
}
358+
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
343359

344360
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
345-
expr.getTarget() instanceof AllocationFunction and
346361
opcode instanceof Opcode::InitializeDynamicAllocation and
347362
tag = OnlyInstructionTag() and
348363
type = getUnknownType()
349364
}
350365

351-
override Instruction getFirstInstruction() {
352-
if expr.getTarget() instanceof AllocationFunction
353-
then result = getInstruction(OnlyInstructionTag())
354-
else result = getChild(0).getFirstInstruction()
355-
}
356-
357366
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
358367
tag = OnlyInstructionTag() and
359368
kind = gotoEdge() and
360-
expr.getTarget() instanceof AllocationFunction and
361369
if exists(getChild(0))
362370
then result = getChild(0).getFirstInstruction()
363371
else result = getParent().getChildSuccessor(this)
@@ -371,23 +379,34 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
371379

372380
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
373381
tag = OnlyInstructionTag() and
374-
result = getTranslatedExpr(expr).getInstruction(CallTag())
382+
if expr instanceof NewOrNewArrayExpr
383+
then result = getTranslatedAllocatorCall(expr).getInstruction(CallTag())
384+
else result = getTranslatedExpr(expr).getInstruction(CallTag())
375385
}
386+
}
376387

377-
/**
378-
* Gets the `TranslatedFunction` containing this expression.
379-
*/
380-
final TranslatedFunction getEnclosingFunction() {
381-
result = getTranslatedFunction(expr.getEnclosingFunction())
382-
}
388+
class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSideEffects {
389+
Call expr;
383390

384-
/**
385-
* Gets the `Function` containing this expression.
386-
*/
387-
override Function getFunction() { result = expr.getEnclosingFunction() }
391+
TranslatedCallSideEffects() { this = TTranslatedCallSideEffects(expr) }
392+
393+
override string toString() { result = "(side effects for " + expr.toString() + ")" }
394+
395+
override Call getExpr() { result = expr }
396+
397+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
398+
399+
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
400+
401+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
402+
403+
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
404+
tag = OnlyInstructionTag() and
405+
result = getTranslatedExpr(expr).getInstruction(CallTag())
406+
}
388407
}
389408

390-
class TranslatedStructorCallSideEffects extends TranslatedSideEffects {
409+
class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects {
391410
TranslatedStructorCallSideEffects() { getParent().(TranslatedStructorCall).hasQualifier() }
392411

393412
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType t) {

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,22 @@ newtype TTranslatedElement =
442442
// The declaration/initialization part of a `ConditionDeclExpr`
443443
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
444444
// The side effects of a `Call`
445-
TTranslatedSideEffects(Call expr) {
446-
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
447-
expr instanceof ConstructorCall or
448-
expr.getTarget() instanceof AllocationFunction
449-
} or // A precise side effect of an argument to a `Call`
445+
TTranslatedCallSideEffects(Call expr) {
446+
// Exclude allocations such as `malloc` (which happen to also be function calls).
447+
// Both `TranslatedCallSideEffects` and `TranslatedAllocationSideEffects` generate
448+
// the same side effects for its children as they both extend the `TranslatedSideEffects`
449+
// class.
450+
// Note: We can separate allocation side effects and call side effects into two
451+
// translated elements as no call can be both a `ConstructorCall` and an `AllocationExpr`.
452+
not expr instanceof AllocationExpr and
453+
(
454+
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
455+
expr instanceof ConstructorCall
456+
)
457+
} or
458+
// The side effects of an allocation, i.e. `new`, `new[]` or `malloc`
459+
TTranslatedAllocationSideEffects(AllocationExpr expr) or
460+
// A precise side effect of an argument to a `Call`
450461
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) {
451462
(
452463
expr = call.getArgument(n).getFullyConverted()

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,11 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
16491649

16501650
final override int getNumberOfArguments() {
16511651
result = expr.getAllocatorCall().getNumberOfArguments()
1652+
or
1653+
// Make sure there's a result even when there is no allocator, as otherwise
1654+
// TranslatedCall::getChild() will not return the side effects for this call.
1655+
not exists(expr.getAllocatorCall()) and
1656+
result = 0
16521657
}
16531658

16541659
final override TranslatedExpr getArgument(int index) {

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+
}

0 commit comments

Comments
 (0)