Skip to content

Commit d7c784e

Browse files
committed
Initial commit of experimental query cpp/guarded-free.
1 parent aa80dd4 commit d7c784e

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
void test()
2+
{
3+
char *foo = malloc(100);
4+
5+
// BAD
6+
if (foo)
7+
free(foo);
8+
9+
// GOOD
10+
free(foo);
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
5+
</overview>
6+
<recommendation>
7+
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
8+
</recommendation>
9+
<example>
10+
<sample src = "GuardedFree.cpp" />
11+
</example>
12+
<references>
13+
<li>
14+
The Open Group Base Specifications Issue 7, 2018 Edition:
15+
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
16+
</li>
17+
</references>
18+
</qhelp>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* @name Guarded Free
3+
* @description NULL-condition guards before function calls to the memory-deallocation
4+
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
5+
* @kind problem
6+
* @problem.severity recommendation
7+
* @precision very-high
8+
* @id cpp/guarded-free
9+
* @tags maintainability
10+
* readability
11+
* experimental
12+
*/
13+
14+
import cpp
15+
16+
class FreeCall extends FunctionCall {
17+
FreeCall() { this.getTarget().hasName("free") }
18+
}
19+
20+
from IfStmt stmt, FreeCall fc, Variable v
21+
where
22+
stmt.getThen() = fc.getEnclosingStmt() and
23+
(
24+
stmt.getCondition() = v.getAnAccess() and
25+
fc.getArgument(0) = v.getAnAccess()
26+
or
27+
exists(PointerDereferenceExpr cond, PointerDereferenceExpr arg |
28+
fc.getArgument(0) = arg and
29+
stmt.getCondition() = cond and
30+
cond.getOperand+() = v.getAnAccess() and
31+
arg.getOperand+() = v.getAnAccess()
32+
)
33+
or
34+
exists(ArrayExpr cond, ArrayExpr arg |
35+
fc.getArgument(0) = arg and
36+
stmt.getCondition() = cond and
37+
cond.getArrayBase+() = v.getAnAccess() and
38+
arg.getArrayBase+() = v.getAnAccess()
39+
)
40+
or
41+
exists(NEExpr eq |
42+
fc.getArgument(0) = v.getAnAccess() and
43+
stmt.getCondition() = eq and
44+
eq.getAnOperand() = v.getAnAccess() and
45+
eq.getAnOperand().getValue() = "0"
46+
)
47+
)
48+
select stmt, "unnecessary NULL check before call to $@", fc, "free"

0 commit comments

Comments
 (0)