Skip to content

Commit 69c7c83

Browse files
authored
Merge pull request #5094 from MathiasVP/promote-UnsignedDifferenceExpressionComparedZero
Promote cpp/unsigned-difference-expression-compared-zero out of experimental
2 parents 7c54512 + cf0e464 commit 69c7c83

12 files changed

Lines changed: 68 additions & 64 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm
2+
* A new query (`cpp/unsigned-difference-expression-compared-zero`) has been added. The query finds unsigned subtractions used in relational comparisons with the value 0.

cpp/config/suites/cpp/correctness

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions
1111
+ semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions
1212
+ semmlecode-cpp-queries/Likely Bugs/OO/UnsafeUseOfThis.ql: /Correctness/Dangerous Conversions
13+
+ semmlecode-cpp-queries/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql: /Correctness/Dangerous Conversions
1314
# Consistent Use
1415
+ semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use
1516
+ semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
unsigned limit = get_limit();
2+
unsigned total = 0;
3+
while (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop.
4+
total += get_data();
5+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
This rule finds relational comparisons between the result of an unsigned subtraction and the value <code>0</code>.
8+
Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the
9+
relational comparison ends up checking whether the result of the subtraction is equal to <code>0</code>.
10+
This is probably not what the programmer intended.
11+
</p>
12+
</overview>
13+
<recommendation>
14+
15+
<p>If a relational comparison is intended, consider casting the result of the subtraction to a signed type.
16+
If the intention was to test for equality, consider replacing the relational comparison with an equality test.
17+
</p>
18+
19+
</recommendation>
20+
<example>
21+
<sample src="UnsignedDifferenceExpressionComparedZero.c" />
22+
23+
</example>
24+
<references>
25+
26+
<li>SEI CERT C Coding Standard:
27+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules">INT02-C. Understand integer conversion rules</a>.
28+
</li>
29+
30+
</references>
31+
</qhelp>

cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql renamed to cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
/**
22
* @name Unsigned difference expression compared to zero
3-
* @description It is highly probable that the condition is wrong if the difference expression has the unsigned type.
4-
* The condition holds in all the cases when difference is not equal to zero. It means that we may use condition not equal.
5-
* But the programmer probably wanted to compare the difference of elements.
3+
* @description A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong.
64
* @kind problem
75
* @id cpp/unsigned-difference-expression-compared-zero
86
* @problem.severity warning
97
* @precision medium
108
* @tags security
9+
* correctness
1110
* external/cwe/cwe-191
1211
*/
1312

@@ -17,24 +16,34 @@ import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1716
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1817
import semmle.code.cpp.controlflow.Guards
1918

19+
/** Holds if `sub` is guarded by a condition which ensures that `left >= right`. */
20+
pragma[noinline]
21+
predicate isGuarded(SubExpr sub, Expr left, Expr right) {
22+
exists(GuardCondition guard |
23+
guard.controls(sub.getBasicBlock(), true) and
24+
guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false)
25+
)
26+
}
27+
2028
/** Holds if `sub` will never be negative. */
2129
predicate nonNegative(SubExpr sub) {
2230
not exprMightOverflowNegatively(sub.getFullyConverted())
2331
or
2432
// The subtraction is guarded by a check of the form `left >= right`.
25-
exists(GuardCondition guard, Expr left, Expr right |
26-
left = globalValueNumber(sub.getLeftOperand()).getAnExpr() and
27-
right = globalValueNumber(sub.getRightOperand()).getAnExpr() and
28-
guard.controls(sub.getBasicBlock(), true) and
29-
guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false)
33+
exists(GVN left, GVN right |
34+
// This is basically a poor man's version of a directional unbind operator.
35+
strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and
36+
strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and
37+
isGuarded(sub, left.getAnExpr(), right.getAnExpr())
3038
)
3139
}
3240

3341
from RelationalOperation ro, SubExpr sub
3442
where
3543
not isFromMacroDefinition(ro) and
44+
not isFromMacroDefinition(sub) and
3645
ro.getLesserOperand().getValue().toInt() = 0 and
3746
ro.getGreaterOperand() = sub and
3847
sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and
3948
not nonNegative(sub)
40-
select ro, "Difference in condition is always greater than or equal to zero"
49+
select ro, "Unsigned subtraction can never be negative."

cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c

Lines changed: 0 additions & 11 deletions
This file was deleted.

cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp

Lines changed: 0 additions & 33 deletions
This file was deleted.

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected

Lines changed: 0 additions & 10 deletions
This file was deleted.

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| test.cpp:6:5:6:13 | ... > ... | Unsigned subtraction can never be negative. |
2+
| test.cpp:10:8:10:24 | ... > ... | Unsigned subtraction can never be negative. |
3+
| test.cpp:15:9:15:25 | ... > ... | Unsigned subtraction can never be negative. |
4+
| test.cpp:32:12:32:20 | ... > ... | Unsigned subtraction can never be negative. |
5+
| test.cpp:39:12:39:20 | ... > ... | Unsigned subtraction can never be negative. |
6+
| test.cpp:47:5:47:13 | ... > ... | Unsigned subtraction can never be negative. |
7+
| test.cpp:55:5:55:13 | ... > ... | Unsigned subtraction can never be negative. |
8+
| test.cpp:62:5:62:13 | ... > ... | Unsigned subtraction can never be negative. |
9+
| test.cpp:69:5:69:13 | ... > ... | Unsigned subtraction can never be negative. |
10+
| test.cpp:75:8:75:16 | ... > ... | Unsigned subtraction can never be negative. |

0 commit comments

Comments
 (0)