Skip to content

Commit 95ddc01

Browse files
authored
Merge pull request github#13502 from rvermeulen/rvermeulen/compare-using-integer-precision
C++: Account for the signedness of the lesser operand in `cpp/comparison-with-wider-type`
2 parents 32045f8 + a6469e4 commit 95ddc01

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,20 @@ Element friendlyLoc(Expr e) {
4545
not e instanceof Access and not e instanceof Call and result = e
4646
}
4747

48+
int getComparisonSizeAdjustment(Expr e) {
49+
if e.getType().(IntegralType).isSigned() then result = 1 else result = 0
50+
}
51+
4852
from Loop l, RelationalOperation rel, VariableAccess small, Expr large
4953
where
5054
small = rel.getLesserOperand() and
5155
large = rel.getGreaterOperand() and
5256
rel = l.getCondition().getAChild*() and
5357
forall(Expr conv | conv = large.getConversion*() |
54-
upperBound(conv).log2() > getComparisonSize(small) * 8
58+
// We adjust the comparison size in the case of a signed integer type.
59+
// This is to exclude the sign bit from the comparison that determines if the small type's size is sufficient to hold
60+
// the value of the larger type determined with range analysis.
61+
upperBound(conv).log2() > (getComparisonSize(small) * 8 - getComparisonSizeAdjustment(small))
5562
) and
5663
// Ignore cases where the smaller type is int or larger
5764
// These are still bugs, but you should need a very large string or array to
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The `cpp/comparison-with-wider-type` query now correctly handles relational operations on signed operators. As a result the query may find more results.

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
| test.c:4:14:4:18 | ... < ... | Comparison between $@ of type char and $@ of wider type int. | test.c:3:7:3:7 | c | c | test.c:2:17:2:17 | x | x |
22
| test.c:9:14:9:18 | ... > ... | Comparison between $@ of type char and $@ of wider type int. | test.c:8:7:8:7 | c | c | test.c:7:17:7:17 | x | x |
33
| test.c:14:14:14:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:13:8:13:8 | s | s | test.c:12:17:12:17 | x | x |
4+
| test.c:42:15:42:29 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:41:9:41:10 | s1 | s1 | test.c:42:20:42:29 | 65535 | 65535 |
45
| test.c:65:14:65:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:64:8:64:8 | s | s | test.c:63:17:63:17 | x | x |
56
| test.c:87:14:87:18 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:84:15:84:15 | x | x |
67
| test.c:91:14:91:23 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:91:18:91:23 | 65280 | 65280 |
@@ -13,3 +14,4 @@
1314
| test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... |
1415
| test.c:128:15:128:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz |
1516
| test.c:139:15:139:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz |
17+
| test.c:156:9:156:14 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:150:8:150:8 | s | s | test.c:151:6:151:7 | sx | sx |

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void test5 () {
3939

4040
void test6() {
4141
short s1;
42-
for (s1 = 0; s1 < 0x0000ffff; s1++) {}
42+
for (s1 = 0; s1 < 0x0000ffff; s1++) {} // BAD
4343
}
4444

4545
void test7(long long l) {
@@ -145,3 +145,22 @@ void test13() {
145145
sz = (unsigned)sx & (unsigned)sy;
146146
for (uc = 0; uc < sz; uc++) {} // GOOD
147147
}
148+
149+
void test14() {
150+
short s = 0;
151+
int sx = 0x7FFF + 1;
152+
153+
// BAD: 's' is compared with a value of a wider type.
154+
// 's' overflows before reaching 'sx',
155+
// causing an infinite loop
156+
while (s < sx) {
157+
s += 1;
158+
}
159+
160+
unsigned int ux = 0;
161+
162+
// GOOD: 'ux' has a type at least as wide as 'max_get'
163+
while (ux < sx) {
164+
ux += 1;
165+
}
166+
}

0 commit comments

Comments
 (0)