Skip to content

Commit 71d528f

Browse files
committed
add bitwise complement
1 parent d994c7c commit 71d528f

File tree

3 files changed

+107
-33
lines changed

3 files changed

+107
-33
lines changed

cpp/src/security/UnsafeImplicitConversions/UnsafeImplicitConversions.ql

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ predicate safeBounds(Expr cast, IntegralType toType) {
3434
}
3535

3636

37-
from IntegralConversion cast, IntegralType fromType, IntegralType toType
37+
from IntegralConversion cast, IntegralType fromType, IntegralType toType, boolean checkBounds, string problemType
3838
where
3939
cast.isImplicit()
4040
and fromType = cast.getExpr().getExplicitlyConverted().getUnspecifiedType()
@@ -43,27 +43,53 @@ where
4343

4444
and (
4545
// truncation
46-
fromType.getSize() > toType.getSize()
46+
(
47+
problemType = "truncation"
48+
and fromType.getSize() > toType.getSize()
49+
and checkBounds = true
50+
)
4751
or
4852
// reinterpretation
4953
(
50-
fromType.getSize() = toType.getSize()
54+
problemType = "reinterpretation"
55+
and fromType.getSize() = toType.getSize()
5156
and
5257
(
5358
(fromType.isUnsigned() and toType.isSigned())
5459
or
5560
(fromType.isSigned() and toType.isUnsigned())
5661
)
62+
and checkBounds = true
5763
)
5864
or
5965
// widening
6066
(
61-
fromType.getSize() < toType.getSize() and fromType.isSigned() and toType.isUnsigned()
67+
fromType.getSize() < toType.getSize()
68+
and
69+
(
70+
(
71+
problemType = "widening"
72+
and fromType.isSigned() and toType.isUnsigned()
73+
and checkBounds = true
74+
)
75+
or
76+
// unsafe promotion
77+
(
78+
problemType = "promotion with bitwise complement"
79+
and exists(ComplementExpr complement |
80+
complement.getOperand().getConversion*() = cast
81+
)
82+
and checkBounds = false
83+
)
84+
)
6285
)
6386
)
6487

65-
// skip if value is in safe range
66-
and not safeBounds(cast.getExpr(), toType)
88+
// skip if value is in safe range, except for ~ (complement)
89+
and (
90+
checkBounds = true implies
91+
not safeBounds(cast.getExpr(), toType)
92+
)
6793

6894
and not (
6995
// skip conversions in arithmetic operations
@@ -93,4 +119,4 @@ where
93119
or
94120
exists(FunctionAccess fc | fc.getTarget() = cast.getEnclosingFunction())
95121
)
96-
select cast, "Implicit cast from " + fromType + " to " + toType + "; bounds are [" + lowerBound(cast.getExpr())+ "; " + upperBound(cast.getExpr()) + "]"
122+
select cast, "Implicit cast from " + fromType + " to " + toType + " (" + problemType + "), bounds are [" + lowerBound(cast.getExpr())+ "; " + upperBound(cast.getExpr()) + "]"
Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
1-
| test.cpp:72:17:72:21 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
2-
| test.cpp:73:20:73:24 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
3-
| test.cpp:74:23:74:27 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
4-
| test.cpp:75:28:75:32 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
5-
| test.cpp:80:36:80:40 | (int)... | Implicit cast from unsigned long to int; bounds are [0; 18446744073709551616] |
6-
| test.cpp:88:17:88:21 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
7-
| test.cpp:94:17:94:21 | (unsigned int)... | Implicit cast from unsigned long to unsigned int; bounds are [4294967297; 4294967297] |
8-
| test.cpp:100:17:100:21 | (unsigned int)... | Implicit cast from unsigned long to unsigned int; bounds are [4294967297; 4294967297] |
9-
| test.cpp:106:17:106:21 | (int)... | Implicit cast from long to int; bounds are [4294967297; 4294967297] |
10-
| test.cpp:114:17:114:17 | (int)... | Implicit cast from unsigned long to int; bounds are [0; 18446744073709551616] |
11-
| test.cpp:121:17:121:21 | (int)... | Implicit cast from unsigned int to int; bounds are [0; 4294967295] |
12-
| test.cpp:121:28:121:28 | (int)... | Implicit cast from unsigned int to int; bounds are [0; 4294967295] |
13-
| test.cpp:127:17:127:21 | (unsigned short)... | Implicit cast from unsigned long to unsigned short; bounds are [4294967297; 4294967297] |
14-
| test.cpp:133:17:133:21 | (int)... | Implicit cast from unsigned long to int; bounds are [4294967297; 4294967297] |
15-
| test.cpp:140:17:140:18 | (unsigned short)... | Implicit cast from unsigned long to unsigned short; bounds are [0; 18446744073709551616] |
16-
| test.cpp:146:17:146:21 | (int)... | Implicit cast from unsigned int to int; bounds are [4294967295; 4294967295] |
17-
| test.cpp:151:17:151:26 | (int)... | Implicit cast from unsigned int to int; bounds are [2147484985; 2147484985] |
18-
| test.cpp:157:17:157:21 | (unsigned int)... | Implicit cast from long to unsigned int; bounds are [-1; -1] |
19-
| test.cpp:163:17:163:50 | (uint16_t)... | Implicit cast from int to unsigned short; bounds are [-51956; -51956] |
20-
| test.cpp:264:12:264:65 | (unsigned int)... | Implicit cast from int to unsigned int; bounds are [-2147483648; 2147483647] |
21-
| test.cpp:270:16:270:31 | (size_t)... | Implicit cast from int to unsigned long; bounds are [-2147483648; 2147483647] |
22-
| test.cpp:271:14:271:14 | (int)... | Implicit cast from unsigned long to int; bounds are [0; 18446744073709551616] |
23-
| test.cpp:289:18:289:18 | (int)... | Implicit cast from unsigned long to int; bounds are [0; 18446744073709551616] |
1+
| test.cpp:72:17:72:21 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
2+
| test.cpp:73:20:73:24 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
3+
| test.cpp:74:23:74:27 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
4+
| test.cpp:75:28:75:32 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
5+
| test.cpp:80:36:80:40 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [0; 18446744073709551616] |
6+
| test.cpp:88:17:88:21 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
7+
| test.cpp:94:17:94:21 | (unsigned int)... | Implicit cast from unsigned long to unsigned int (truncation), bounds are [4294967297; 4294967297] |
8+
| test.cpp:100:17:100:21 | (unsigned int)... | Implicit cast from unsigned long to unsigned int (truncation), bounds are [4294967297; 4294967297] |
9+
| test.cpp:106:17:106:21 | (int)... | Implicit cast from long to int (truncation), bounds are [4294967297; 4294967297] |
10+
| test.cpp:114:17:114:17 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [0; 18446744073709551616] |
11+
| test.cpp:121:17:121:21 | (int)... | Implicit cast from unsigned int to int (reinterpretation), bounds are [0; 4294967295] |
12+
| test.cpp:121:28:121:28 | (int)... | Implicit cast from unsigned int to int (reinterpretation), bounds are [0; 4294967295] |
13+
| test.cpp:127:17:127:21 | (unsigned short)... | Implicit cast from unsigned long to unsigned short (truncation), bounds are [4294967297; 4294967297] |
14+
| test.cpp:133:17:133:21 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [4294967297; 4294967297] |
15+
| test.cpp:140:17:140:18 | (unsigned short)... | Implicit cast from unsigned long to unsigned short (truncation), bounds are [0; 18446744073709551616] |
16+
| test.cpp:146:17:146:21 | (int)... | Implicit cast from unsigned int to int (reinterpretation), bounds are [4294967295; 4294967295] |
17+
| test.cpp:151:17:151:26 | (int)... | Implicit cast from unsigned int to int (reinterpretation), bounds are [2147484985; 2147484985] |
18+
| test.cpp:157:17:157:21 | (unsigned int)... | Implicit cast from long to unsigned int (truncation), bounds are [-1; -1] |
19+
| test.cpp:163:17:163:50 | (uint16_t)... | Implicit cast from int to unsigned short (truncation), bounds are [-51956; -51956] |
20+
| test.cpp:170:24:170:24 | (unsigned int)... | Implicit cast from short to unsigned int (widening), bounds are [-2; -2] |
21+
| test.cpp:176:18:176:20 | (int)... | Implicit cast from unsigned short to int (promotion with bitwise complement), bounds are [19; 19] |
22+
| test.cpp:277:12:277:65 | (unsigned int)... | Implicit cast from int to unsigned int (reinterpretation), bounds are [-2147483648; 2147483647] |
23+
| test.cpp:283:16:283:31 | (size_t)... | Implicit cast from int to unsigned long (widening), bounds are [-2147483648; 2147483647] |
24+
| test.cpp:284:14:284:14 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [0; 18446744073709551616] |
25+
| test.cpp:302:18:302:18 | (int)... | Implicit cast from unsigned long to int (truncation), bounds are [0; 18446744073709551616] |
26+
| test.cpp:308:35:308:37 | (int)... | Implicit cast from unsigned short to int (promotion with bitwise complement), bounds are [19; 19] |

cpp/test/query-tests/security/UnsafeImplicitConversions/test.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,19 @@ void test15() {
163163
test_func_9((uint16_t)large - (uint16_t)0xcafe);
164164
}
165165

166+
// Implicit widening in usual arithmetic conversions
167+
void test16() {
168+
short a = -2;
169+
unsigned int b = 0x13;
170+
unsigned short c = a & b;
171+
}
172+
173+
// Implicit type promotion with binary complement
174+
void test17() {
175+
unsigned short val = 0x13;
176+
int val2 = (~val) >> 3;
177+
}
178+
166179

167180
/*
168181
* Tests for False Positives
@@ -267,8 +280,8 @@ unsigned int complex_const(void) {
267280

268281
int test_fp11(int argc, size_t c) {
269282
int a = argc * 2;
270-
size_t b = max_int(1500, a);
271-
int h2 = c;
283+
size_t b = max_int(1500, a); // ok but reported (Value Range Analysis limitation)
284+
int h2 = c; // ok but reported (Value Range Analysis limitation)
272285
if (h2 > 0) {
273286
c = 44;
274287
int w = c;
@@ -286,10 +299,35 @@ int test_fp11(int argc, size_t c) {
286299
c = (c + 3) & ~3 | 0xf;
287300
b += c;
288301

289-
int result = b; // ok, b's upper bound is known
302+
int result = b; // ok but reported (Value Range Analysis limitation)
290303
return result;
291304
}
292305

306+
void test_fp12() {
307+
unsigned short val = 0x13;
308+
int val2 = (unsigned short) (~val) >> 3; // TODO: exclude explicit conversions
309+
}
310+
311+
void test_fp13() {
312+
unsigned short val = 0x13;
313+
int val2 = -val;
314+
}
315+
316+
void test_fp14() {
317+
uint64_t large = (uint64_t)0x100000001;
318+
test_func_1((int)large);
319+
test_func_1(static_cast<int>(large));
320+
test_func_1(int{large});
321+
}
322+
323+
void test_fp15() {
324+
short a = -2;
325+
unsigned int b = 0x13;
326+
unsigned short c = (unsigned int)a & b;
327+
}
328+
329+
330+
293331
int main(int argc, char **argv) {
294332
uint64_t large;
295333
large = 0x100000001;
@@ -309,6 +347,8 @@ int main(int argc, char **argv) {
309347
test13();
310348
test14();
311349
test15();
350+
test16();
351+
test17();
312352

313353
test_fp1(large);
314354
test_fp2();
@@ -324,6 +364,11 @@ int main(int argc, char **argv) {
324364
// reported, because Value Range Analysis limitations
325365
test_fp11(argc, 22);
326366
test_fp11(argc, argc);
367+
368+
test_fp12();
369+
test_fp13();
370+
test_fp14();
371+
test_fp15();
327372

328373
return 0;
329374
}

0 commit comments

Comments
 (0)