Skip to content

Commit 6aa4005

Browse files
committed
C++: Use member predicates on parameterized module parameters now that it's available in the language.
1 parent f4b5f39 commit 6aa4005

File tree

1 file changed

+78
-112
lines changed

1 file changed

+78
-112
lines changed

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

Lines changed: 78 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,34 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
206206
}
207207

208208
/** A `Function` that is a call target of an allocation. */
209-
private signature class CallAllocationExprTarget extends Function;
209+
private signature class CallAllocationExprTarget extends Function {
210+
/**
211+
* Gets the index of the input pointer argument to be reallocated, if
212+
* this is a `realloc` function.
213+
*/
214+
int getReallocPtrArg();
215+
216+
/**
217+
* Gets the index of the argument for the allocation size, if any. The actual
218+
* allocation size is the value of this argument multiplied by the result of
219+
* `getSizeMult()`, in bytes.
220+
*/
221+
int getSizeArg();
222+
223+
/**
224+
* Gets the index of an argument that multiplies the allocation size given
225+
* by `getSizeArg`, if any.
226+
*/
227+
int getSizeMult();
228+
229+
/**
230+
* Holds if this allocation requires a
231+
* corresponding deallocation of some sort (most do, but `alloca` for example
232+
* does not). If it is unclear, we default to no (for example a placement `new`
233+
* allocation may or may not require a corresponding `delete`).
234+
*/
235+
predicate requiresDealloc();
236+
}
210237

211238
/**
212239
* This module abstracts over the type of allocation call-targets and provides a
@@ -220,118 +247,68 @@ private signature class CallAllocationExprTarget extends Function;
220247
* function using various heuristics.
221248
*/
222249
private module CallAllocationExprBase<CallAllocationExprTarget Target> {
223-
/** A module that contains the collection of member-predicates required on `Target`. */
224-
signature module Param {
225-
/**
226-
* Gets the index of the input pointer argument to be reallocated, if
227-
* this is a `realloc` function.
228-
*/
229-
int getReallocPtrArg(Target target);
230-
231-
/**
232-
* Gets the index of the argument for the allocation size, if any. The actual
233-
* allocation size is the value of this argument multiplied by the result of
234-
* `getSizeMult()`, in bytes.
235-
*/
236-
int getSizeArg(Target target);
237-
238-
/**
239-
* Gets the index of an argument that multiplies the allocation size given
240-
* by `getSizeArg`, if any.
241-
*/
242-
int getSizeMult(Target target);
243-
244-
/**
245-
* Holds if this allocation requires a
246-
* corresponding deallocation of some sort (most do, but `alloca` for example
247-
* does not). If it is unclear, we default to no (for example a placement `new`
248-
* allocation may or may not require a corresponding `delete`).
249-
*/
250-
predicate requiresDealloc(Target target);
251-
}
252-
253250
/**
254-
* A module that abstracts over a collection of predicates in
255-
* the `Param` module). This should really be member-predicates
256-
* on `CallAllocationExprTarget`, but we cannot yet write this in QL.
251+
* An allocation expression that is a function call, such as call to `malloc`.
257252
*/
258-
module With<Param P> {
259-
private import P
260-
261-
/**
262-
* An allocation expression that is a function call, such as call to `malloc`.
263-
*/
264-
class CallAllocationExprImpl instanceof FunctionCall {
265-
Target target;
266-
267-
CallAllocationExprImpl() {
268-
target = this.getTarget() and
269-
// realloc(ptr, 0) only frees the pointer
270-
not (
271-
exists(getReallocPtrArg(target)) and
272-
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
273-
) and
274-
// these are modeled directly (and more accurately), avoid duplication
275-
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
276-
}
277-
278-
string toString() { result = super.toString() }
279-
280-
Expr getSizeExprImpl() {
281-
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
282-
if exists(getSizeMult(target))
283-
then result = sizeExpr
284-
else
285-
exists(Expr lengthExpr |
286-
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
287-
result = lengthExpr
288-
)
289-
)
290-
}
291-
292-
int getSizeMultImpl() {
293-
// malloc with multiplier argument that is a constant
294-
result = super.getArgument(getSizeMult(target)).getValue().toInt()
295-
or
296-
// malloc with no multiplier argument
297-
not exists(getSizeMult(target)) and
298-
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
299-
}
300-
301-
int getSizeBytesImpl() {
302-
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
303-
}
304-
305-
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
306-
307-
Type getAllocatedElementTypeImpl() {
308-
result =
309-
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
310-
not result instanceof VoidType
311-
}
312-
313-
predicate requiresDeallocImpl() { requiresDealloc(target) }
253+
class CallAllocationExprImpl instanceof FunctionCall {
254+
Target target;
255+
256+
CallAllocationExprImpl() {
257+
target = this.getTarget() and
258+
// realloc(ptr, 0) only frees the pointer
259+
not (
260+
exists(target.getReallocPtrArg()) and
261+
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
262+
) and
263+
// these are modeled directly (and more accurately), avoid duplication
264+
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
314265
}
315-
}
316-
}
317266

318-
private module CallAllocationExpr {
319-
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
320-
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
267+
string toString() { result = super.toString() }
268+
269+
Expr getSizeExprImpl() {
270+
exists(Expr sizeExpr | sizeExpr = super.getArgument(target.getSizeArg()) |
271+
if exists(target.getSizeMult())
272+
then result = sizeExpr
273+
else
274+
exists(Expr lengthExpr |
275+
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
276+
result = lengthExpr
277+
)
278+
)
279+
}
280+
281+
int getSizeMultImpl() {
282+
// malloc with multiplier argument that is a constant
283+
result = super.getArgument(target.getSizeMult()).getValue().toInt()
284+
or
285+
// malloc with no multiplier argument
286+
not exists(target.getSizeMult()) and
287+
deconstructSizeExpr(super.getArgument(target.getSizeArg()), _, result)
288+
}
289+
290+
int getSizeBytesImpl() {
291+
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
292+
}
321293

322-
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
294+
Expr getReallocPtrImpl() { result = super.getArgument(target.getReallocPtrArg()) }
323295

324-
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
296+
Type getAllocatedElementTypeImpl() {
297+
result =
298+
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
299+
not result instanceof VoidType
300+
}
325301

326-
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
302+
predicate requiresDeallocImpl() { target.requiresDealloc() }
327303
}
304+
}
328305

306+
private module CallAllocationExpr {
329307
/**
330308
* A class that provides the implementation of `AllocationExpr` for an allocation
331309
* that calls an `AllocationFunction`.
332310
*/
333-
private class Base =
334-
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
311+
private class Base = CallAllocationExprBase<AllocationFunction>::CallAllocationExprImpl;
335312

336313
class CallAllocationExpr extends AllocationExpr, Base {
337314
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
@@ -452,22 +429,11 @@ private module HeuristicAllocation {
452429
override predicate requiresDealloc() { none() }
453430
}
454431

455-
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
456-
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
457-
458-
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
459-
460-
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
461-
462-
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
463-
}
464-
465432
/**
466433
* A class that provides the implementation of `AllocationExpr` for an allocation
467434
* that calls an `HeuristicAllocationFunction`.
468435
*/
469-
private class Base =
470-
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
436+
private class Base = CallAllocationExprBase<HeuristicAllocationFunction>::CallAllocationExprImpl;
471437

472438
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
473439
override Expr getSizeExpr() { result = super.getSizeExprImpl() }

0 commit comments

Comments
 (0)