Skip to content

Commit 18d4772

Browse files
authored
Merge pull request #2463 from geoffw0/overflowcalc
CPP: Allocation and Deallocation libraries
2 parents a13748f + 939979d commit 18d4772

File tree

26 files changed

+710
-235
lines changed

26 files changed

+710
-235
lines changed

change-notes/1.24/analysis-cpp.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
1313

1414
| **Query** | **Expected impact** | **Change** |
1515
|----------------------------|------------------------|------------------------------------------------------------------|
16+
| Buffer not sufficient for string (`cpp/overflow-calculated`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
17+
| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
18+
| Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
19+
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
1620
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
1721
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
1822

1923
## Changes to libraries
2024

25+
* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model allocation such as `new` expressions and calls to `malloc`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface.
26+
* Created the `semmle.code.cpp.models.interfaces.Deallocation` library to model deallocation such as `delete` expressions and calls to `free`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface.
2127
* The new class `StackVariable` should be used in place of `LocalScopeVariable`
2228
in most cases. The difference is that `StackVariable` does not include
2329
variables declared with `static` or `thread_local`.
Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import semmle.code.cpp.pointsto.PointsTo
22

33
private predicate freed(Expr e) {
4-
exists(FunctionCall fc, Expr arg |
5-
freeCall(fc, arg) and
6-
arg = e
7-
)
8-
or
9-
exists(DeleteExpr de | de.getExpr() = e)
10-
or
11-
exists(DeleteArrayExpr de | de.getExpr() = e)
4+
e = any(DeallocationExpr de).getFreedExpr()
125
or
136
exists(ExprCall c |
147
// cautiously assume that any ExprCall could be a freeCall.
@@ -22,7 +15,4 @@ class FreedExpr extends PointsToExpr {
2215
override predicate interesting() { freed(this) }
2316
}
2417

25-
predicate allocMayBeFreed(Expr alloc) {
26-
isAllocationExpr(alloc) and
27-
anythingPointsTo(alloc)
28-
}
18+
predicate allocMayBeFreed(AllocationExpr alloc) { anythingPointsTo(alloc) }

cpp/ql/src/Critical/MemoryMayNotBeFreed.ql

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ predicate mayCallFunction(Expr call, Function f) {
2424

2525
predicate allocCallOrIndirect(Expr e) {
2626
// direct alloc call
27-
isAllocationExpr(e) and
27+
e.(AllocationExpr).requiresDealloc() and
2828
// We are only interested in alloc calls that are
2929
// actually freed somehow, as MemoryNeverFreed
3030
// will catch those that aren't.
@@ -53,8 +53,7 @@ predicate allocCallOrIndirect(Expr e) {
5353
* can cause memory leaks.
5454
*/
5555
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
56-
reallocCall.getTarget().hasGlobalOrStdName("realloc") and
57-
reallocCall.getArgument(0) = v.getAnAccess() and
56+
reallocCall.(AllocationExpr).getReallocPtr() = v.getAnAccess() and
5857
(
5958
exists(Variable newV, ControlFlowNode node |
6059
// a realloc followed by a null check at 'node' (return the non-null
@@ -71,23 +70,19 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
7170
or
7271
// a realloc(ptr, 0), which always succeeds and frees
7372
// (return the realloc itself)
74-
reallocCall.getArgument(1).getValue() = "0" and
73+
reallocCall.(AllocationExpr).getReallocPtr().getValue() = "0" and
7574
verified = reallocCall
7675
)
7776
}
7877

7978
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
8079
// direct free call
81-
freeCall(n, v.getAnAccess()) and
82-
not n.(FunctionCall).getTarget().hasGlobalOrStdName("realloc")
80+
n.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
81+
not exists(n.(AllocationExpr).getReallocPtr())
8382
or
8483
// verified realloc call
8584
verifiedRealloc(_, v, n)
8685
or
87-
n.(DeleteExpr).getExpr() = v.getAnAccess()
88-
or
89-
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
90-
or
9186
exists(FunctionCall midcall, Function mid, int arg |
9287
// indirect free call
9388
n.(Call).getArgument(arg) = v.getAnAccess() and

cpp/ql/src/Critical/MemoryNeverFreed.ql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import MemoryFreed
1313

14-
from Expr alloc
15-
where isAllocationExpr(alloc) and not allocMayBeFreed(alloc)
14+
from AllocationExpr alloc
15+
where
16+
alloc.requiresDealloc() and
17+
not allocMayBeFreed(alloc)
1618
select alloc, "This memory is never freed"

cpp/ql/src/Critical/OverflowCalculated.ql

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,16 @@
1111
*/
1212

1313
import cpp
14-
15-
class MallocCall extends FunctionCall {
16-
MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") }
17-
18-
Expr getAllocatedSize() {
19-
if this.getArgument(0) instanceof VariableAccess
20-
then
21-
exists(StackVariable v, ControlFlowNode def |
22-
definitionUsePair(v, def, this.getArgument(0)) and
23-
exprDefinition(v, def, result)
24-
)
25-
else result = this.getArgument(0)
26-
}
27-
}
14+
import semmle.code.cpp.dataflow.DataFlow
15+
import semmle.code.cpp.models.interfaces.Allocation
2816

2917
predicate spaceProblem(FunctionCall append, string msg) {
30-
exists(MallocCall malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer |
18+
exists(
19+
AllocationExpr malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer
20+
|
3121
add.getAChild() = strlen and
3222
exists(add.getAChild().getValue()) and
33-
malloc.getAllocatedSize() = add and
23+
DataFlow::localExprFlow(add, malloc.getSizeExpr()) and
3424
buffer.getAnAccess() = strlen.getStringExpr() and
3525
(
3626
insert.getTarget().hasGlobalOrStdName("strcpy") or

cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,11 @@
1717
import cpp
1818
import semmle.code.cpp.dataflow.DataFlow
1919
import semmle.code.cpp.models.interfaces.ArrayFunction
20+
import semmle.code.cpp.models.interfaces.Allocation
2021

21-
class MallocCall extends FunctionCall {
22-
MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") }
23-
24-
Expr getAllocatedSize() { result = this.getArgument(0) }
25-
}
26-
27-
predicate terminationProblem(MallocCall malloc, string msg) {
22+
predicate terminationProblem(AllocationExpr malloc, string msg) {
2823
// malloc(strlen(...))
29-
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getAllocatedSize())) and
24+
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getSizeExpr())) and
3025
// flows into a null-terminated string function
3126
exists(ArrayFunction af, FunctionCall fc, int arg |
3227
DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and
Lines changed: 22 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,207 +1,64 @@
11
import cpp
2+
import semmle.code.cpp.models.interfaces.Allocation
3+
import semmle.code.cpp.models.interfaces.Deallocation
24

35
/**
46
* A library routine that allocates memory.
7+
*
8+
* DEPRECATED: Use the `AllocationFunction` class instead of this predicate.
59
*/
6-
predicate allocationFunction(Function f) {
7-
exists(string name |
8-
f.hasGlobalOrStdName(name) and
9-
(
10-
name = "malloc" or
11-
name = "calloc" or
12-
name = "realloc" or
13-
name = "strdup" or
14-
name = "wcsdup"
15-
)
16-
or
17-
f.hasGlobalName(name) and
18-
(
19-
name = "_strdup" or
20-
name = "_wcsdup" or
21-
name = "_mbsdup" or
22-
name = "ExAllocatePool" or
23-
name = "ExAllocatePoolWithTag" or
24-
name = "ExAllocatePoolWithTagPriority" or
25-
name = "ExAllocatePoolWithQuota" or
26-
name = "ExAllocatePoolWithQuotaTag" or
27-
name = "ExAllocateFromLookasideListEx" or
28-
name = "ExAllocateFromPagedLookasideList" or
29-
name = "ExAllocateFromNPagedLookasideList" or
30-
name = "ExAllocateTimer" or
31-
name = "IoAllocateMdl" or
32-
name = "IoAllocateWorkItem" or
33-
name = "IoAllocateErrorLogEntry" or
34-
name = "MmAllocateContiguousMemory" or
35-
name = "MmAllocateContiguousNodeMemory" or
36-
name = "MmAllocateContiguousMemorySpecifyCache" or
37-
name = "MmAllocateContiguousMemorySpecifyCacheNode" or
38-
name = "MmAllocateNonCachedMemory" or
39-
name = "MmAllocateMappingAddress" or
40-
name = "MmAllocatePagesForMdl" or
41-
name = "MmAllocatePagesForMdlEx" or
42-
name = "MmAllocateNodePagesForMdlEx" or
43-
name = "MmMapLockedPagesWithReservedMapping" or
44-
name = "MmMapLockedPages" or
45-
name = "MmMapLockedPagesSpecifyCache" or
46-
name = "LocalAlloc" or
47-
name = "LocalReAlloc" or
48-
name = "GlobalAlloc" or
49-
name = "GlobalReAlloc" or
50-
name = "HeapAlloc" or
51-
name = "HeapReAlloc" or
52-
name = "VirtualAlloc" or
53-
name = "CoTaskMemAlloc" or
54-
name = "CoTaskMemRealloc" or
55-
name = "kmem_alloc" or
56-
name = "kmem_zalloc" or
57-
name = "pool_get" or
58-
name = "pool_cache_get"
59-
)
60-
)
61-
}
10+
deprecated predicate allocationFunction(Function f) { f instanceof AllocationFunction }
6211

6312
/**
6413
* A call to a library routine that allocates memory.
14+
*
15+
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
6516
*/
66-
predicate allocationCall(FunctionCall fc) {
67-
allocationFunction(fc.getTarget()) and
68-
(
69-
// realloc(ptr, 0) only frees the pointer
70-
fc.getTarget().hasGlobalOrStdName("realloc") implies not fc.getArgument(1).getValue() = "0"
71-
)
72-
}
17+
deprecated predicate allocationCall(FunctionCall fc) { fc instanceof AllocationExpr }
7318

7419
/**
7520
* A library routine that frees memory.
7621
*/
77-
predicate freeFunction(Function f, int argNum) {
78-
exists(string name |
79-
f.hasGlobalName(name) and
80-
(
81-
name = "free" and argNum = 0
82-
or
83-
name = "realloc" and argNum = 0
84-
or
85-
name = "kmem_free" and argNum = 0
86-
or
87-
name = "pool_put" and argNum = 1
88-
or
89-
name = "pool_cache_put" and argNum = 1
90-
)
91-
or
92-
f.hasGlobalOrStdName(name) and
93-
(
94-
name = "ExFreePoolWithTag" and argNum = 0
95-
or
96-
name = "ExFreeToLookasideListEx" and argNum = 1
97-
or
98-
name = "ExFreeToPagedLookasideList" and argNum = 1
99-
or
100-
name = "ExFreeToNPagedLookasideList" and argNum = 1
101-
or
102-
name = "ExDeleteTimer" and argNum = 0
103-
or
104-
name = "IoFreeMdl" and argNum = 0
105-
or
106-
name = "IoFreeWorkItem" and argNum = 0
107-
or
108-
name = "IoFreeErrorLogEntry" and argNum = 0
109-
or
110-
name = "MmFreeContiguousMemory" and argNum = 0
111-
or
112-
name = "MmFreeContiguousMemorySpecifyCache" and argNum = 0
113-
or
114-
name = "MmFreeNonCachedMemory" and argNum = 0
115-
or
116-
name = "MmFreeMappingAddress" and argNum = 0
117-
or
118-
name = "MmFreePagesFromMdl" and argNum = 0
119-
or
120-
name = "MmUnmapReservedMapping" and argNum = 0
121-
or
122-
name = "MmUnmapLockedPages" and argNum = 0
123-
or
124-
name = "LocalFree" and argNum = 0
125-
or
126-
name = "GlobalFree" and argNum = 0
127-
or
128-
name = "HeapFree" and argNum = 2
129-
or
130-
name = "VirtualFree" and argNum = 0
131-
or
132-
name = "CoTaskMemFree" and argNum = 0
133-
or
134-
name = "SysFreeString" and argNum = 0
135-
or
136-
name = "LocalReAlloc" and argNum = 0
137-
or
138-
name = "GlobalReAlloc" and argNum = 0
139-
or
140-
name = "HeapReAlloc" and argNum = 2
141-
or
142-
name = "CoTaskMemRealloc" and argNum = 0
143-
)
144-
)
145-
}
22+
predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunction).getFreedArg() }
14623

14724
/**
14825
* A call to a library routine that frees memory.
14926
*/
150-
predicate freeCall(FunctionCall fc, Expr arg) {
151-
exists(int argNum |
152-
freeFunction(fc.getTarget(), argNum) and
153-
arg = fc.getArgument(argNum)
154-
)
155-
}
27+
predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getFreedExpr() }
15628

15729
/**
15830
* Is e some kind of allocation or deallocation (`new`, `alloc`, `realloc`, `delete`, `free` etc)?
15931
*/
160-
predicate isMemoryManagementExpr(Expr e) { isAllocationExpr(e) or isDeallocationExpr(e) }
32+
predicate isMemoryManagementExpr(Expr e) { isAllocationExpr(e) or e instanceof DeallocationExpr }
16133

16234
/**
16335
* Is e an allocation from stdlib.h (`malloc`, `realloc` etc)?
36+
*
37+
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
16438
*/
165-
predicate isStdLibAllocationExpr(Expr e) { allocationCall(e) }
39+
deprecated predicate isStdLibAllocationExpr(Expr e) { allocationCall(e) }
16640

16741
/**
16842
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc)?
16943
*/
17044
predicate isAllocationExpr(Expr e) {
171-
allocationCall(e)
45+
e.(FunctionCall) instanceof AllocationExpr
17246
or
17347
e = any(NewOrNewArrayExpr new | not exists(new.getPlacementPointer()))
17448
}
17549

17650
/**
17751
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc) with a fixed size?
52+
*
53+
* DEPRECATED: Use `AllocationExpr.getSizeBytes()` instead.
17854
*/
179-
predicate isFixedSizeAllocationExpr(Expr allocExpr, int size) {
180-
exists(FunctionCall fc, string name | fc = allocExpr and name = fc.getTarget().getName() |
181-
name = "malloc" and
182-
size = fc.getArgument(0).getValue().toInt()
183-
or
184-
name = "alloca" and
185-
size = fc.getArgument(0).getValue().toInt()
186-
or
187-
name = "calloc" and
188-
size = fc.getArgument(0).getValue().toInt() * fc.getArgument(1).getValue().toInt()
189-
or
190-
name = "realloc" and
191-
size = fc.getArgument(1).getValue().toInt() and
192-
size > 0 // realloc(ptr, 0) only frees the pointer
193-
)
194-
or
195-
size = allocExpr.(NewExpr).getAllocatedType().getSize()
196-
or
197-
size = allocExpr.(NewArrayExpr).getAllocatedType().getSize()
55+
deprecated predicate isFixedSizeAllocationExpr(Expr allocExpr, int size) {
56+
size = allocExpr.(AllocationExpr).getSizeBytes()
19857
}
19958

20059
/**
20160
* Is e some kind of deallocation (`delete`, `free`, `realloc` etc)?
61+
*
62+
* DEPRECATED: Use `DeallocationExpr` instead.
20263
*/
203-
predicate isDeallocationExpr(Expr e) {
204-
freeCall(e, _) or
205-
e instanceof DeleteExpr or
206-
e instanceof DeleteArrayExpr
207-
}
64+
deprecated predicate isDeallocationExpr(Expr e) { e instanceof DeallocationExpr }

cpp/ql/src/semmle/code/cpp/commons/Buffer.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
8585
)
8686
or
8787
// buffer is a fixed size dynamic allocation
88-
isFixedSizeAllocationExpr(bufferExpr, result) and
88+
result = bufferExpr.(AllocationExpr).getSizeBytes() and
8989
why = bufferExpr
9090
or
9191
exists(DataFlow::ExprNode bufferExprNode |

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
private import implementations.Allocation
2+
private import implementations.Deallocation
13
private import implementations.Fread
24
private import implementations.IdentityFunction
35
private import implementations.Inet

0 commit comments

Comments
 (0)