Skip to content

Commit 293e646

Browse files
committed
AllocationExpr.getSizeMult() now analyzes the size expression of function calls.
This yields more precise size information in a lot of the common cases of C allocation code, as the common pattern malloc(count * sizeof(type)) is now understood.
1 parent 247fc42 commit 293e646

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

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

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,24 @@ class OperatorNewAllocationFunction extends AllocationFunction {
255255
}
256256
}
257257

258+
pragma[inline]
259+
private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof) {
260+
sizeExpr instanceof MulExpr and
261+
exists(SizeofOperator sizeofOp |
262+
sizeofOp = sizeExpr.(MulExpr).getAnOperand() and
263+
lengthExpr = sizeExpr.(MulExpr).getAnOperand() and
264+
sizeofOp != lengthExpr and
265+
sizeof = sizeofOp.getValue().toInt()
266+
)
267+
or
268+
not exists(int s, SizeofOperator sizeofOp |
269+
sizeofOp = sizeExpr.(MulExpr).getAnOperand() and
270+
s = sizeofOp.(SizeofOperator).getValue().toInt()
271+
) and
272+
lengthExpr = sizeExpr and
273+
sizeof = 1
274+
}
275+
258276
/**
259277
* An allocation expression that is a function call, such as call to `malloc`.
260278
*/
@@ -272,15 +290,29 @@ class CallAllocationExpr extends AllocationExpr, FunctionCall {
272290
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
273291
}
274292

275-
override Expr getSizeExpr() { result = getArgument(target.getSizeArg()) }
293+
override Expr getSizeExpr() {
294+
exists(Expr sizeExpr | sizeExpr = getArgument(target.getSizeArg()) |
295+
if exists(target.getSizeMult())
296+
then result = sizeExpr
297+
else (
298+
exists(Expr lengthExpr |
299+
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
300+
result = lengthExpr
301+
)
302+
or
303+
not exists(Expr lengthExpr | deconstructSizeExpr(sizeExpr, lengthExpr, _)) and
304+
result = sizeExpr
305+
)
306+
)
307+
}
276308

277309
override int getSizeMult() {
278310
// malloc with multiplier argument that is a constant
279311
result = getArgument(target.getSizeMult()).getValue().toInt()
280312
or
281313
// malloc with no multiplier argument
282314
not exists(target.getSizeMult()) and
283-
result = 1
315+
deconstructSizeExpr(getArgument(target.getSizeArg()), _, result)
284316
}
285317

286318
override int getSizeBytes() { result = getSizeExpr().getValue().toInt() * getSizeMult() }

cpp/ql/test/library-tests/allocators/allocators.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ allocationExprs
8686
| allocators.cpp:144:13:144:31 | new[] | getSizeExpr = x, getSizeMult = 900, requiresDealloc |
8787
| allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc |
8888
| allocators.cpp:156:3:156:8 | call to malloc | getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc |
89-
| allocators.cpp:157:3:157:8 | call to malloc | getSizeBytes = 20, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
89+
| allocators.cpp:157:3:157:8 | call to malloc | getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc |
9090
| allocators.cpp:158:3:158:8 | call to malloc | getSizeExpr = count, getSizeMult = 1, requiresDealloc |
91-
| allocators.cpp:159:3:159:8 | call to malloc | getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
91+
| allocators.cpp:159:3:159:8 | call to malloc | getSizeExpr = count, getSizeMult = 4, requiresDealloc |
9292
| allocators.cpp:160:3:160:8 | call to malloc | getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc |
93-
| allocators.cpp:161:3:161:8 | call to malloc | getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc |
93+
| allocators.cpp:161:3:161:8 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc |
9494
deallocationFunctions
9595
| allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 |
9696
| allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 |

0 commit comments

Comments
 (0)