Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8f7ff1a

Browse files
committed
Adds another redundant null check rule
1 parent fe0c5a9 commit 8f7ff1a

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
void test(char *arg1, int *arg2) {
2+
if (arg1[0] == 'A') {
3+
if (arg2 != NULL) {
4+
*arg2 = 42;
5+
}
6+
}
7+
if (arg1[1] == 'B')
8+
{
9+
*arg2 = 54;
10+
}
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's
8+
likely either the check is not required and can be removed, or it should be added before the dereference
9+
so that a null pointer dereference does not occur.</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>A check should be added to before the dereference, in a way that prevents a null pointer value from
14+
being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.</p>
15+
</recommendation>
16+
17+
<example>
18+
<sample src="RedundantNullCheckParam.cpp" />
19+
</example>
20+
21+
<references>
22+
<li>
23+
<a href="https://www.owasp.org/index.php/Null_Dereference">
24+
Null Dereference
25+
</a>
26+
</li>
27+
</references>
28+
29+
</qhelp>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @name Redundant null check or missing null check
3+
* @description Checking a parameter for nullness in one path,
4+
* and not in another is likely to be a sign that either
5+
* the check can be removed, or added in the other case.
6+
* @kind problem
7+
* @id cpp/redundant-null-check-param
8+
* @problem.severity recommendation
9+
* @tags reliability
10+
* security
11+
* external/cwe/cwe-476
12+
*/
13+
14+
import cpp
15+
16+
predicate blockDominates(Block check, Block access) {
17+
check.getLocation().getStartLine() <= access.getLocation().getStartLine() and
18+
check.getLocation().getEndLine() >= access.getLocation().getEndLine()
19+
}
20+
21+
predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) {
22+
checked =
23+
any(VariableAccess va |
24+
va.getTarget() = unchecked.getTarget()
25+
) and
26+
//Simple test if the first access in this code path is dereferenced
27+
not dereferenced(checked) and
28+
blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock())
29+
}
30+
31+
pragma[noinline]
32+
predicate candidateResultUnchecked(VariableAccess unchecked) {
33+
not isCheckedInstruction(unchecked, _)
34+
}
35+
36+
pragma[noinline]
37+
predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop, Parameter param) {
38+
//not dereferenced to check against pointer, not its pointed value
39+
not dereferenced(check) and
40+
//assert macros are not taken into account
41+
not check.isInMacroExpansion() and
42+
// is part of a comarison against some constant NULL
43+
eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue and
44+
// this function parameter is not overwritten
45+
count(param.getAnAssignment()) = 0
46+
}
47+
48+
from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param
49+
where
50+
// a dereference
51+
dereferenced(unchecked) and
52+
// for a function parameter
53+
unchecked.getTarget() = param and
54+
check.getTarget() = param and
55+
// which is once checked
56+
candidateResultChecked(check, eqop, param) and
57+
// and which has not been checked before in this code path
58+
candidateResultUnchecked(unchecked)
59+
select check, "This null check is redundant because the value is $@ ", unchecked, "dereferenced here"

0 commit comments

Comments
 (0)