@@ -205,57 +205,149 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
205
205
sizeof = 1
206
206
}
207
207
208
+ /** A `Function` that is a call target of an allocation. */
209
+ private signature class CallAllocationExprTarget extends Function ;
210
+
208
211
/**
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.
210
221
*/
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 ) ;
223
251
}
224
252
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
+ )
233
289
)
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
+ }
235
315
}
316
+ }
236
317
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 ( ) }
245
321
246
- override int getSizeBytes ( ) {
247
- result = this .getSizeExpr ( ) .getValue ( ) .toInt ( ) * this .getSizeMult ( )
248
- }
322
+ int getSizeArg ( AllocationFunction f ) { result = f .getSizeArg ( ) }
249
323
250
- override Expr getReallocPtr ( ) { result = this . getArgument ( target . getReallocPtrArg ( ) ) }
324
+ int getSizeMult ( AllocationFunction f ) { result = f . getSizeMult ( ) }
251
325
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 ( ) }
256
327
}
257
328
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
+ }
259
351
}
260
352
261
353
/**
@@ -294,3 +386,99 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
294
386
295
387
override predicate requiresDealloc ( ) { not exists ( this .getPlacementPointer ( ) ) }
296
388
}
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