Skip to content

Commit 6966453

Browse files
authored
Merge pull request github#4881 from ihsinme/main
CPP: Add query for CWE-401 memory leak on unsuccessful call to realloc function
2 parents 29935e1 + bbd3f76 commit 6966453

File tree

6 files changed

+406
-0
lines changed

6 files changed

+406
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// BAD: on unsuccessful call to realloc, we will lose a pointer to a valid memory block
2+
if (currentSize < newSize)
3+
{
4+
buffer = (unsigned char *)realloc(buffer, newSize);
5+
}
6+
7+
8+
9+
// GOOD: this way we will exclude possible memory leak
10+
unsigned char * tmp;
11+
if (currentSize < newSize)
12+
{
13+
tmp = (unsigned char *)realloc(buffer, newSize);
14+
}
15+
if (tmp == NULL)
16+
{
17+
free(buffer);
18+
}
19+
else
20+
buffer = tmp;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Memory leak on failed call to realloc.
7+
The expression <code>mem = realloc (mem, size)</code> is potentially dangerous, if the call fails, we will lose the pointer to the memory block.
8+
An unsuccessful call is possible not only when trying to allocate a large amount of memory, but also when the process memory is strongly segmented.</p>
9+
10+
<p>False positives include code in which immediately after calling the realloc function, the pointer is manipulated without first checking for validity.
11+
In this case, an exception will occur in the program and it will terminate.
12+
But from the point of view of safe coding, these places require the attention of developers.
13+
At this stage, false positives are also possible in situations where the exception handling is quite complicated and occurs outside the base block in which memory is redistributed.</p>
14+
15+
</overview>
16+
<recommendation>
17+
18+
<p>We recommend storing the result in a temporary variable and eliminating memory leak.</p>
19+
20+
</recommendation>
21+
<example>
22+
<p>The following example demonstrates an erroneous and corrected use of the <code>realloc</code> function.</p>
23+
<sample src="MemoryLeakOnFailedCallToRealloc.c" />
24+
25+
</example>
26+
<references>
27+
28+
<li>
29+
CERT C++ Coding Standard:
30+
<a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM51-CPP.+Properly+deallocate+dynamically+allocated+resources">MEM51-CPP. Properly deallocate dynamically allocated resources</a>.
31+
</li>
32+
<li>
33+
CERT C Coding Standard:
34+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/WIN30-C.+Properly+pair+allocation+and+deallocation+functions">WIN30-C. Properly pair allocation and deallocation functions</a>.
35+
</li>
36+
37+
</references>
38+
</qhelp>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @name Memory leak on failed call to realloc
3+
* @description The expression mem = realloc (mem, size) is potentially dangerous, if the call fails, we will lose the pointer to the memory block.
4+
* We recommend storing the result in a temporary variable and eliminating memory leak.
5+
* @kind problem
6+
* @id cpp/memory-leak-on-failed-call-to-realloc
7+
* @problem.severity warning
8+
* @precision medium
9+
* @tags correctness
10+
* security
11+
* external/cwe/cwe-401
12+
*/
13+
14+
import cpp
15+
16+
/**
17+
* A call to `realloc` of the form `v = realloc(v, size)`, for some variable `v`.
18+
*/
19+
class ReallocCallLeak extends FunctionCall {
20+
Variable v;
21+
22+
ReallocCallLeak() {
23+
exists(AssignExpr ex, VariableAccess va1, VariableAccess va2 |
24+
this.getTarget().hasName("realloc") and
25+
this = ex.getRValue() and
26+
va1 = ex.getLValue() and
27+
va2 = this.getArgument(0) and
28+
va1 = v.getAnAccess() and
29+
va2 = v.getAnAccess()
30+
)
31+
}
32+
33+
predicate isExistsIfWithExitCall() {
34+
exists(IfStmt ifc |
35+
this.getArgument(0) = v.getAnAccess() and
36+
ifc.getCondition().getAChild*() = v.getAnAccess() and
37+
ifc.getEnclosingFunction() = this.getEnclosingFunction() and
38+
ifc.getLocation().getStartLine() >= this.getArgument(0).getLocation().getStartLine() and
39+
exists(FunctionCall fc |
40+
fc.getTarget().hasName("exit") and
41+
fc.getEnclosingFunction() = this.getEnclosingFunction() and
42+
(ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc)
43+
)
44+
or
45+
exists(FunctionCall fc, FunctionCall ftmp1, FunctionCall ftmp2 |
46+
ftmp1.getTarget().hasName("exit") and
47+
ftmp2.(ControlFlowNode).getASuccessor*() = ftmp1 and
48+
fc = ftmp2.getEnclosingFunction().getACallToThisFunction() and
49+
fc.getEnclosingFunction() = this.getEnclosingFunction() and
50+
(ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc)
51+
)
52+
)
53+
}
54+
55+
predicate isExistsAssertWithArgumentCall() {
56+
exists(FunctionCall fc |
57+
fc.getTarget().hasName("__assert_fail") and
58+
this.getEnclosingFunction() = fc.getEnclosingFunction() and
59+
fc.getLocation().getStartLine() > this.getArgument(0).getLocation().getEndLine() and
60+
fc.getArgument(0).toString().matches("%" + this.getArgument(0).toString() + "%")
61+
)
62+
}
63+
}
64+
65+
from ReallocCallLeak rcl
66+
where
67+
not rcl.isExistsIfWithExitCall() and
68+
not rcl.isExistsAssertWithArgumentCall()
69+
select rcl, "possible loss of original pointer on unsuccessful call realloc"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:34:29:34:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
2+
| test.c:63:29:63:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
3+
| test.c:139:29:139:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
4+
| test.c:186:29:186:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql

0 commit comments

Comments
 (0)