Skip to content

Commit 35948b0

Browse files
authored
Merge branch 'main' into dilan-java/guidance-exectainted
2 parents bff2633 + 42a97b2 commit 35948b0

File tree

20 files changed

+1714
-46
lines changed

20 files changed

+1714
-46
lines changed

cpp/ql/lib/experimental/semmle/code/cpp/dataflow/ProductFlow.qll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,18 @@ module ProductFlow {
133133
this.isAdditionalFlowStep2(node1, node2)
134134
}
135135

136+
/**
137+
* Holds if data flow into `node` is prohibited in the first projection of the product
138+
* dataflow graph.
139+
*/
140+
predicate isBarrierIn1(DataFlow::Node node) { none() }
141+
142+
/**
143+
* Holds if data flow into `node` is prohibited in the second projection of the product
144+
* dataflow graph.
145+
*/
146+
predicate isBarrierIn2(DataFlow::Node node) { none() }
147+
136148
predicate hasFlowPath(
137149
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
138150
DataFlow2::PathNode sink2
@@ -169,6 +181,10 @@ module ProductFlow {
169181
) {
170182
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
171183
}
184+
185+
override predicate isBarrierIn(DataFlow::Node node) {
186+
exists(Configuration conf | conf.isBarrierIn1(node))
187+
}
172188
}
173189

174190
class Conf2 extends DataFlow2::Configuration {
@@ -202,9 +218,14 @@ module ProductFlow {
202218
) {
203219
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
204220
}
221+
222+
override predicate isBarrierIn(DataFlow::Node node) {
223+
exists(Configuration conf | conf.isBarrierIn2(node))
224+
}
205225
}
206226
}
207227

228+
pragma[nomagic]
208229
private predicate reachableInterprocEntry(
209230
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
210231
DataFlow::PathNode node1, DataFlow2::PathNode node2

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

Lines changed: 227 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -205,57 +205,149 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
205205
sizeof = 1
206206
}
207207

208+
/** A `Function` that is a call target of an allocation. */
209+
private signature class CallAllocationExprTarget extends Function;
210+
208211
/**
209-
* An allocation expression that is a function call, such as call to `malloc`.
212+
* This module abstracts over the type of allocation call-targets and provides a
213+
* class `CallAllocationExprImpl` which contains the implementation of the various
214+
* predicates required by the `Allocation` class.
215+
*
216+
* This module is then instantiated for two types of allocation call-targets:
217+
* - `AllocationFunction`: Functions that we've explicitly modeled as functions that
218+
* perform allocations (i.e., `malloc`).
219+
* - `HeuristicAllocationFunction`: Functions that we deduce as behaving like an allocation
220+
* function using various heuristics.
210221
*/
211-
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
212-
AllocationFunction target;
213-
214-
CallAllocationExpr() {
215-
target = this.getTarget() and
216-
// realloc(ptr, 0) only frees the pointer
217-
not (
218-
exists(target.getReallocPtrArg()) and
219-
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
220-
) and
221-
// these are modeled directly (and more accurately), avoid duplication
222-
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
222+
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);
223251
}
224252

225-
override Expr getSizeExpr() {
226-
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
227-
if exists(target.getSizeMult())
228-
then result = sizeExpr
229-
else
230-
exists(Expr lengthExpr |
231-
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
232-
result = lengthExpr
253+
/**
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.
257+
*/
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+
)
233289
)
234-
)
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) }
314+
}
235315
}
316+
}
236317

237-
override int getSizeMult() {
238-
// malloc with multiplier argument that is a constant
239-
result = this.getArgument(target.getSizeMult()).getValue().toInt()
240-
or
241-
// malloc with no multiplier argument
242-
not exists(target.getSizeMult()) and
243-
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
244-
}
318+
private module CallAllocationExpr {
319+
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
320+
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
245321

246-
override int getSizeBytes() {
247-
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
248-
}
322+
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
249323

250-
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
324+
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
251325

252-
override Type getAllocatedElementType() {
253-
result =
254-
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
255-
not result instanceof VoidType
326+
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
256327
}
257328

258-
override predicate requiresDealloc() { target.requiresDealloc() }
329+
/**
330+
* A class that provides the implementation of `AllocationExpr` for an allocation
331+
* that calls an `AllocationFunction`.
332+
*/
333+
private class Base =
334+
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
335+
336+
class CallAllocationExpr extends AllocationExpr, Base {
337+
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
338+
339+
override int getSizeMult() { result = super.getSizeMultImpl() }
340+
341+
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
342+
343+
override predicate requiresDealloc() { super.requiresDeallocImpl() }
344+
345+
override int getSizeBytes() { result = super.getSizeBytesImpl() }
346+
347+
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
348+
349+
override string toString() { result = AllocationExpr.super.toString() }
350+
}
259351
}
260352

261353
/**
@@ -294,3 +386,99 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
294386

295387
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
296388
}
389+
390+
private module HeuristicAllocation {
391+
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
392+
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
393+
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
394+
395+
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
396+
397+
override int getSizeBytes() { result = AllocationExpr.super.getSizeBytes() }
398+
399+
override Expr getReallocPtr() { result = AllocationExpr.super.getReallocPtr() }
400+
401+
override Type getAllocatedElementType() {
402+
result = AllocationExpr.super.getAllocatedElementType()
403+
}
404+
405+
override predicate requiresDealloc() { AllocationExpr.super.requiresDealloc() }
406+
}
407+
408+
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
409+
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
410+
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
411+
412+
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
413+
414+
override int getReallocPtrArg() { result = AllocationFunction.super.getReallocPtrArg() }
415+
416+
override predicate requiresDealloc() { AllocationFunction.super.requiresDealloc() }
417+
}
418+
419+
private int getAnUnsignedParameter(Function f) {
420+
f.getParameter(result).getUnspecifiedType().(IntegralType).isUnsigned()
421+
}
422+
423+
private int getAPointerParameter(Function f) {
424+
f.getParameter(result).getUnspecifiedType() instanceof PointerType
425+
}
426+
427+
/**
428+
* A class that uses heuristics to find additional allocation functions. The required are as follows:
429+
* 1. The word `alloc` must appear in the function name
430+
* 2. The function must return a pointer type
431+
* 3. There must be a unique parameter of unsigned integral type.
432+
*/
433+
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
434+
int sizeArg;
435+
436+
HeuristicAllocationFunctionByName() {
437+
Function.super.getName().matches("%alloc%") and
438+
Function.super.getUnspecifiedType() instanceof PointerType and
439+
sizeArg = unique( | | getAnUnsignedParameter(this))
440+
}
441+
442+
override int getSizeArg() { result = sizeArg }
443+
444+
override int getReallocPtrArg() {
445+
Function.super.getName().matches("%realloc%") and
446+
result = unique( | | getAPointerParameter(this))
447+
}
448+
449+
override predicate requiresDealloc() { none() }
450+
}
451+
452+
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
453+
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
454+
455+
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
456+
457+
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
458+
459+
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
460+
}
461+
462+
/**
463+
* A class that provides the implementation of `AllocationExpr` for an allocation
464+
* that calls an `HeuristicAllocationFunction`.
465+
*/
466+
private class Base =
467+
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
468+
469+
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
470+
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
471+
472+
override int getSizeMult() { result = super.getSizeMultImpl() }
473+
474+
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
475+
476+
override predicate requiresDealloc() { super.requiresDeallocImpl() }
477+
478+
override int getSizeBytes() { result = super.getSizeBytesImpl() }
479+
480+
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
481+
482+
override string toString() { result = HeuristicAllocationExpr.super.toString() }
483+
}
484+
}

0 commit comments

Comments
 (0)