Skip to content

Commit b471879

Browse files
authored
Merge pull request #17986 from jketema/guarded-free2
C++: Reduce number of FPs `cpp/guarded-free` and turn `if(x) { free(x) }` cases from FNs to TPs
2 parents 6a3e34c + 84f3e6a commit b471879

File tree

3 files changed

+31
-14
lines changed

3 files changed

+31
-14
lines changed

cpp/ql/src/experimental/Best Practices/GuardedFree.ql

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,31 @@ class FreeCall extends FunctionCall {
1818
FreeCall() { this.getTarget().hasGlobalName("free") }
1919
}
2020

21+
predicate blockContainsPreprocessorBranches(BasicBlock bb) {
22+
exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc |
23+
bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation()
24+
|
25+
bbLoc.getFile() = ppb.getFile() and
26+
bbLoc.getStartLine() < ppbLoc.getStartLine() and
27+
ppbLoc.getEndLine() < bbLoc.getEndLine()
28+
)
29+
}
30+
2131
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
2232
where
2333
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
2434
fc.getArgument(0) = v.getAnAccess() and
25-
bb = fc.getEnclosingStmt()
35+
bb = fc.getBasicBlock() and
36+
(
37+
// No block statement: if (x) free(x);
38+
bb = fc.getEnclosingStmt()
39+
or
40+
// Block statement with a single nested statement: if (x) { free(x); }
41+
strictcount(bb.(BlockStmt).getAStmt()) = 1
42+
) and
43+
strictcount(BasicBlock bb2 | gc.ensuresEq(_, 0, bb2, _) | bb2) = 1 and
44+
not fc.isInMacroExpansion() and
45+
not blockContainsPreprocessorBranches(bb) and
46+
not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and
47+
not exists(CommaExpr c | c.getAChild*() = fc)
2648
select gc, "unnecessary NULL check before call to $@", fc, "free"
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
| test.cpp:5:7:5:7 | x | unnecessary NULL check before call to $@ | test.cpp:6:5:6:8 | call to free | free |
2-
| test.cpp:23:7:23:7 | x | unnecessary NULL check before call to $@ | test.cpp:26:5:26:8 | call to free | free |
3-
| test.cpp:31:7:31:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
4-
| test.cpp:31:7:31:24 | ... \|\| ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
5-
| test.cpp:31:8:31:8 | x | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free |
6-
| test.cpp:94:12:94:12 | x | unnecessary NULL check before call to $@ | test.cpp:94:3:94:13 | call to free | free |
7-
| test.cpp:98:7:98:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free |
8-
| test.cpp:98:8:98:8 | x | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free |
2+
| test.cpp:10:7:10:7 | x | unnecessary NULL check before call to $@ | test.cpp:11:5:11:8 | call to free | free |
3+
| test.cpp:42:7:42:7 | x | unnecessary NULL check before call to $@ | test.cpp:43:5:43:8 | call to free | free |
4+
| test.cpp:49:7:49:7 | x | unnecessary NULL check before call to $@ | test.cpp:50:5:50:8 | call to free | free |
95
| test.cpp:106:7:106:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:107:5:107:8 | call to free | free |
10-
| test.cpp:113:7:113:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:114:17:114:20 | call to free | free |

cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ void test2(int *x) {
2020
}
2121

2222
void test3(int *x, bool b) {
23-
if (x) { // GOOD [FALSE POSITIVE]: x is being accessed in the body of the if
23+
if (x) { // GOOD: x is being accessed in the body of the if
2424
if (b)
2525
*x = 42;
2626
free(x);
2727
}
2828
}
2929

3030
bool test4(char *x, char *y) {
31-
if (!x || strcmp(x, y)) { // GOOD [FALSE POSITIVE]: x is being accessed in the guard and return value depends on x
31+
if (!x || strcmp(x, y)) { // GOOD: x is being accessed in the guard and return value depends on x
3232
free(x);
3333
return true;
3434
}
@@ -91,11 +91,11 @@ void test10(char *x) {
9191
if (x) free(x);
9292

9393
void test11(char *x) {
94-
TRY_FREE(x) // BAD
94+
TRY_FREE(x) // BAD [NOT DETECTED]
9595
}
9696

9797
bool test12(char *x) {
98-
if (!x) // GOOD [FALSE POSITIVE]: return value depends on x
98+
if (!x) // GOOD: return value depends on x
9999
return false;
100100

101101
free(x);
@@ -110,6 +110,6 @@ void test13(char *x) {
110110
void inspect(char *x);
111111

112112
void test14(char *x) {
113-
if (x != nullptr) // GOOD [FALSE POSITIVE]: x might be accessed in the first operand of the comma operator
113+
if (x != nullptr) // GOOD: x might be accessed in the first operand of the comma operator
114114
inspect(x), free(x);
115115
}

0 commit comments

Comments
 (0)