@@ -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