diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll index a1fa08daa7d..00b241bc4fa 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Allocation.qll @@ -206,7 +206,34 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof } /** A `Function` that is a call target of an allocation. */ -private signature class CallAllocationExprTarget extends Function; +private signature class CallAllocationExprTarget extends Function { + /** + * Gets the index of the input pointer argument to be reallocated, if + * this is a `realloc` function. + */ + int getReallocPtrArg(); + + /** + * Gets the index of the argument for the allocation size, if any. The actual + * allocation size is the value of this argument multiplied by the result of + * `getSizeMult()`, in bytes. + */ + int getSizeArg(); + + /** + * Gets the index of an argument that multiplies the allocation size given + * by `getSizeArg`, if any. + */ + int getSizeMult(); + + /** + * Holds if this allocation requires a + * corresponding deallocation of some sort (most do, but `alloca` for example + * does not). If it is unclear, we default to no (for example a placement `new` + * allocation may or may not require a corresponding `delete`). + */ + predicate requiresDealloc(); +} /** * This module abstracts over the type of allocation call-targets and provides a @@ -220,118 +247,68 @@ private signature class CallAllocationExprTarget extends Function; * function using various heuristics. */ private module CallAllocationExprBase { - /** A module that contains the collection of member-predicates required on `Target`. */ - signature module Param { - /** - * Gets the index of the input pointer argument to be reallocated, if - * this is a `realloc` function. - */ - int getReallocPtrArg(Target target); - - /** - * Gets the index of the argument for the allocation size, if any. The actual - * allocation size is the value of this argument multiplied by the result of - * `getSizeMult()`, in bytes. - */ - int getSizeArg(Target target); - - /** - * Gets the index of an argument that multiplies the allocation size given - * by `getSizeArg`, if any. - */ - int getSizeMult(Target target); - - /** - * Holds if this allocation requires a - * corresponding deallocation of some sort (most do, but `alloca` for example - * does not). If it is unclear, we default to no (for example a placement `new` - * allocation may or may not require a corresponding `delete`). - */ - predicate requiresDealloc(Target target); - } - /** - * A module that abstracts over a collection of predicates in - * the `Param` module). This should really be member-predicates - * on `CallAllocationExprTarget`, but we cannot yet write this in QL. + * An allocation expression that is a function call, such as call to `malloc`. */ - module With { - private import P + class CallAllocationExprImpl instanceof FunctionCall { + Target target; - /** - * An allocation expression that is a function call, such as call to `malloc`. - */ - class CallAllocationExprImpl instanceof FunctionCall { - Target target; - - CallAllocationExprImpl() { - target = this.getTarget() and - // realloc(ptr, 0) only frees the pointer - not ( - exists(getReallocPtrArg(target)) and - this.getArgument(getSizeArg(target)).getValue().toInt() = 0 - ) and - // these are modeled directly (and more accurately), avoid duplication - not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this) - } - - string toString() { result = super.toString() } - - Expr getSizeExprImpl() { - exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) | - if exists(getSizeMult(target)) - then result = sizeExpr - else - exists(Expr lengthExpr | - deconstructSizeExpr(sizeExpr, lengthExpr, _) and - result = lengthExpr - ) - ) - } - - int getSizeMultImpl() { - // malloc with multiplier argument that is a constant - result = super.getArgument(getSizeMult(target)).getValue().toInt() - or - // malloc with no multiplier argument - not exists(getSizeMult(target)) and - deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result) - } - - int getSizeBytesImpl() { - result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl() - } - - Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) } - - Type getAllocatedElementTypeImpl() { - result = - super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and - not result instanceof VoidType - } - - predicate requiresDeallocImpl() { requiresDealloc(target) } + CallAllocationExprImpl() { + target = this.getTarget() and + // realloc(ptr, 0) only frees the pointer + not ( + exists(target.getReallocPtrArg()) and + this.getArgument(target.getSizeArg()).getValue().toInt() = 0 + ) and + // these are modeled directly (and more accurately), avoid duplication + not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this) } + + string toString() { result = super.toString() } + + Expr getSizeExprImpl() { + exists(Expr sizeExpr | sizeExpr = super.getArgument(target.getSizeArg()) | + if exists(target.getSizeMult()) + then result = sizeExpr + else + exists(Expr lengthExpr | + deconstructSizeExpr(sizeExpr, lengthExpr, _) and + result = lengthExpr + ) + ) + } + + int getSizeMultImpl() { + // malloc with multiplier argument that is a constant + result = super.getArgument(target.getSizeMult()).getValue().toInt() + or + // malloc with no multiplier argument + not exists(target.getSizeMult()) and + deconstructSizeExpr(super.getArgument(target.getSizeArg()), _, result) + } + + int getSizeBytesImpl() { + result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl() + } + + Expr getReallocPtrImpl() { result = super.getArgument(target.getReallocPtrArg()) } + + Type getAllocatedElementTypeImpl() { + result = + super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and + not result instanceof VoidType + } + + predicate requiresDeallocImpl() { target.requiresDealloc() } } } private module CallAllocationExpr { - private module Param implements CallAllocationExprBase::Param { - int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() } - - int getSizeArg(AllocationFunction f) { result = f.getSizeArg() } - - int getSizeMult(AllocationFunction f) { result = f.getSizeMult() } - - predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() } - } - /** * A class that provides the implementation of `AllocationExpr` for an allocation * that calls an `AllocationFunction`. */ - private class Base = - CallAllocationExprBase::With::CallAllocationExprImpl; + private class Base = CallAllocationExprBase::CallAllocationExprImpl; class CallAllocationExpr extends AllocationExpr, Base { override Expr getSizeExpr() { result = super.getSizeExprImpl() } @@ -452,22 +429,11 @@ private module HeuristicAllocation { override predicate requiresDealloc() { none() } } - private module Param implements CallAllocationExprBase::Param { - int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() } - - int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() } - - int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() } - - predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() } - } - /** * A class that provides the implementation of `AllocationExpr` for an allocation * that calls an `HeuristicAllocationFunction`. */ - private class Base = - CallAllocationExprBase::With::CallAllocationExprImpl; + private class Base = CallAllocationExprBase::CallAllocationExprImpl; private class CallAllocationExpr extends HeuristicAllocationExpr, Base { override Expr getSizeExpr() { result = super.getSizeExprImpl() }