Skip to content

Commit b7dc26e

Browse files
authored
Merge pull request #3072 from geoffw0/gezero2
C++: Improvement to cpp/unsigned-comparison-zero
2 parents 9454188 + 40db92b commit b7dc26e

File tree

5 files changed

+76
-7
lines changed

5 files changed

+76
-7
lines changed

change-notes/1.24/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
2525
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
2626
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |
2727
| Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. |
28+
| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. |
2829

2930
## Changes to libraries
3031

cpp/ql/src/Likely Bugs/Arithmetic/UnsignedGEZero.qll

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@ class ConstantZero extends Expr {
1919
* Holds if `candidate` is an expression such that if it's unsigned then we
2020
* want an alert at `ge`.
2121
*/
22-
private predicate lookForUnsignedAt(GEExpr ge, Expr candidate) {
23-
// Base case: `candidate >= 0`
24-
ge.getRightOperand() instanceof ConstantZero and
25-
candidate = ge.getLeftOperand().getFullyConverted() and
26-
// left operand was a signed or unsigned IntegralType before conversions
22+
private predicate lookForUnsignedAt(RelationalOperation ge, Expr candidate) {
23+
// Base case: `candidate >= 0` (or `0 <= candidate`)
24+
(
25+
ge instanceof GEExpr or
26+
ge instanceof LEExpr
27+
) and
28+
ge.getLesserOperand() instanceof ConstantZero and
29+
candidate = ge.getGreaterOperand().getFullyConverted() and
30+
// left/greater operand was a signed or unsigned IntegralType before conversions
2731
// (not a pointer, checking a pointer >= 0 is an entirely different mistake)
2832
// (not an enum, as the fully converted type of an enum is compiler dependent
2933
// so checking an enum >= 0 is always reasonable)
30-
ge.getLeftOperand().getUnderlyingType() instanceof IntegralType
34+
ge.getGreaterOperand().getUnderlyingType() instanceof IntegralType
3135
or
3236
// Recursive case: `...(largerType)candidate >= 0`
3337
exists(Conversion conversion |
@@ -37,7 +41,7 @@ private predicate lookForUnsignedAt(GEExpr ge, Expr candidate) {
3741
)
3842
}
3943

40-
class UnsignedGEZero extends GEExpr {
44+
class UnsignedGEZero extends ComparisonOperation {
4145
UnsignedGEZero() {
4246
exists(Expr ue |
4347
lookForUnsignedAt(this, ue) and

cpp/ql/test/query-tests/Likely Bugs/Arithmetic/UnsignedGEZero/UnsignedGEZero.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,29 @@ void myFunction() {
112112
assert(CHECK_RANGE(ui, 0, 10)); // reasonable use
113113
assert(UI >= ZERO); // violation (not detected)
114114
assert(ui GE 0); // violation
115+
116+
if ((unsigned char)si >= 0) { // violation
117+
}
118+
if ((unsigned char)(signed int)si >= 0) { // violation
119+
}
120+
if ((signed int)(unsigned char)si >= 0) { // violation
121+
}
122+
if ((unsigned char)(signed char)si >= 0) { // violation
123+
}
124+
if ((signed char)(unsigned char)si >= 0) {
125+
}
126+
127+
if ((signed int)(unsigned char)(signed int)si >= 0) { // violation
128+
}
129+
if ((signed char)(unsigned char)(signed int)si >= 0) {
130+
}
131+
if ((signed int)(unsigned char)(signed char)si >= 0) { // violation
132+
}
133+
134+
if (ui <= 0) {
135+
}
136+
if (0 <= ui) { // violation
137+
}
138+
if (0 < ui) {
139+
}
115140
}

cpp/ql/test/query-tests/Likely Bugs/Arithmetic/UnsignedGEZero/UnsignedGEZero.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,29 @@ void myFunction() {
112112
assert(CHECK_RANGE(ui, 0, 10)); // reasonable use
113113
assert(UI >= ZERO); // violation (not detected)
114114
assert(ui GE 0); // violation
115+
116+
if ((unsigned char)si >= 0) { // violation
117+
}
118+
if ((unsigned char)(signed int)si >= 0) { // violation
119+
}
120+
if ((signed int)(unsigned char)si >= 0) { // violation
121+
}
122+
if ((unsigned char)(signed char)si >= 0) { // violation
123+
}
124+
if ((signed char)(unsigned char)si >= 0) {
125+
}
126+
127+
if ((signed int)(unsigned char)(signed int)si >= 0) { // violation
128+
}
129+
if ((signed char)(unsigned char)(signed int)si >= 0) {
130+
}
131+
if ((signed int)(unsigned char)(signed char)si >= 0) { // violation
132+
}
133+
134+
if (ui <= 0) {
135+
}
136+
if (0 <= ui) { // violation
137+
}
138+
if (0 < ui) {
139+
}
115140
}

cpp/ql/test/query-tests/Likely Bugs/Arithmetic/UnsignedGEZero/UnsignedGEZero.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
| UnsignedGEZero.c:101:9:101:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
1515
| UnsignedGEZero.c:111:9:111:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
1616
| UnsignedGEZero.c:114:9:114:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
17+
| UnsignedGEZero.c:116:6:116:27 | ... >= ... | Pointless comparison of unsigned value to zero. |
18+
| UnsignedGEZero.c:118:6:118:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
19+
| UnsignedGEZero.c:120:6:120:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
20+
| UnsignedGEZero.c:122:6:122:40 | ... >= ... | Pointless comparison of unsigned value to zero. |
21+
| UnsignedGEZero.c:127:6:127:51 | ... >= ... | Pointless comparison of unsigned value to zero. |
22+
| UnsignedGEZero.c:131:6:131:52 | ... >= ... | Pointless comparison of unsigned value to zero. |
23+
| UnsignedGEZero.c:136:6:136:12 | ... <= ... | Pointless comparison of unsigned value to zero. |
1724
| UnsignedGEZero.cpp:40:6:40:12 | ... >= ... | Pointless comparison of unsigned value to zero. |
1825
| UnsignedGEZero.cpp:48:6:48:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
1926
| UnsignedGEZero.cpp:54:6:54:12 | ... >= ... | Pointless comparison of unsigned value to zero. |
@@ -29,3 +36,10 @@
2936
| UnsignedGEZero.cpp:101:9:101:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
3037
| UnsignedGEZero.cpp:111:9:111:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
3138
| UnsignedGEZero.cpp:114:9:114:15 | ... >= ... | Pointless comparison of unsigned value to zero. |
39+
| UnsignedGEZero.cpp:116:6:116:27 | ... >= ... | Pointless comparison of unsigned value to zero. |
40+
| UnsignedGEZero.cpp:118:6:118:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
41+
| UnsignedGEZero.cpp:120:6:120:39 | ... >= ... | Pointless comparison of unsigned value to zero. |
42+
| UnsignedGEZero.cpp:122:6:122:40 | ... >= ... | Pointless comparison of unsigned value to zero. |
43+
| UnsignedGEZero.cpp:127:6:127:51 | ... >= ... | Pointless comparison of unsigned value to zero. |
44+
| UnsignedGEZero.cpp:131:6:131:52 | ... >= ... | Pointless comparison of unsigned value to zero. |
45+
| UnsignedGEZero.cpp:136:6:136:12 | ... <= ... | Pointless comparison of unsigned value to zero. |

0 commit comments

Comments
 (0)