Skip to content

Commit 812315d

Browse files
committed
C++: Use existing getSize / getRootType to find more generous bounds for arrays inside classes (though it sometimes fails, costing us TPs).
1 parent 07004bd commit 812315d

File tree

5 files changed

+23
-46
lines changed

5 files changed

+23
-46
lines changed

cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ private int getSize(VariableAccess va) {
105105
private int isSource(Expr bufferExpr, Element why) {
106106
exists(Variable bufferVar | bufferVar = bufferExpr.(VariableAccess).getTarget() |
107107
// buffer is a fixed size array
108-
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
108+
exists(bufferVar.getUnspecifiedType().(ArrayType).getSize()) and
109+
result = getSize(bufferExpr) and // more generous than .getSize() itself, when the array is a class field or similar.
109110
why = bufferVar and
110111
not memberMayBeVarSize(_, bufferVar) and
111112
not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild*() = bufferExpr) and

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
| tests.cpp:285:3:285:8 | call to memset | This 'memset' operation accesses 128 bytes but the $@ is only 64 bytes. | tests.cpp:283:12:283:23 | new[] | destination buffer |
1818
| tests.cpp:292:3:292:8 | call to memset | This 'memset' operation accesses 11 bytes but the $@ is only 10 bytes. | tests.cpp:289:8:289:12 | array | destination buffer |
1919
| tests.cpp:310:2:310:7 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer |
20-
| tests.cpp:312:2:312:7 | call to memset | This 'memset' operation accesses 17 bytes but the $@ is only 16 bytes. | tests.cpp:298:7:298:12 | buffer | destination buffer |
2120
| tests.cpp:314:2:314:7 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:299:6:299:10 | field | destination buffer |
2221
| tests.cpp:348:2:348:14 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:342:7:342:15 | charArray | array |
2322
| tests.cpp:351:2:351:14 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array |
@@ -83,30 +82,12 @@
8382
| tests.cpp:886:5:886:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer |
8483
| tests.cpp:887:5:887:10 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer |
8584
| tests.cpp:888:5:888:10 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 4 bytes. | tests.cpp:833:12:833:12 | u | destination buffer |
86-
| tests.cpp:913:2:913:17 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:897:7:897:8 | as | array |
87-
| tests.cpp:915:2:915:17 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 40 bytes. | tests.cpp:897:7:897:8 | as | array |
88-
| tests.cpp:916:2:916:18 | access to array | This array indexing operation accesses byte offset 403 but the $@ is only 40 bytes. | tests.cpp:897:7:897:8 | as | array |
89-
| tests.cpp:917:2:917:17 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:897:7:897:8 | as | array |
90-
| tests.cpp:919:2:919:17 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 40 bytes. | tests.cpp:897:7:897:8 | as | array |
91-
| tests.cpp:920:2:920:18 | access to array | This array indexing operation accesses byte offset 403 but the $@ is only 40 bytes. | tests.cpp:897:7:897:8 | as | array |
92-
| tests.cpp:924:2:924:11 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:903:4:903:5 | ds | array |
93-
| tests.cpp:927:2:927:16 | access to array | This array indexing operation accesses byte offset 4 but the $@ is only 4 bytes. | tests.cpp:902:8:902:9 | cs | array |
94-
| tests.cpp:928:2:928:17 | access to array | This array indexing operation accesses byte offset 39 but the $@ is only 4 bytes. | tests.cpp:902:8:902:9 | cs | array |
95-
| tests.cpp:929:2:929:17 | access to array | This array indexing operation accesses byte offset 40 but the $@ is only 4 bytes. | tests.cpp:902:8:902:9 | cs | array |
96-
| tests.cpp:932:2:932:16 | access to array | This array indexing operation accesses byte offset 4 but the $@ is only 4 bytes. | tests.cpp:902:8:902:9 | cs | array |
97-
| tests.cpp:934:2:934:17 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:906:11:906:12 | xs | array |
98-
| tests.cpp:936:2:936:17 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 40 bytes. | tests.cpp:906:11:906:12 | xs | array |
99-
| tests.cpp:937:2:937:18 | access to array | This array indexing operation accesses byte offset 403 but the $@ is only 40 bytes. | tests.cpp:906:11:906:12 | xs | array |
100-
| tests.cpp:938:2:938:17 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:906:11:906:12 | xs | array |
101-
| tests.cpp:940:2:940:17 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 40 bytes. | tests.cpp:906:11:906:12 | xs | array |
102-
| tests.cpp:941:2:941:18 | access to array | This array indexing operation accesses byte offset 403 but the $@ is only 40 bytes. | tests.cpp:906:11:906:12 | xs | array |
10385
| tests.cpp:984:2:984:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array |
10486
| tests.cpp:989:2:989:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array |
10587
| tests.cpp:994:2:994:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array |
10688
| tests.cpp:1001:2:1001:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array |
10789
| tests.cpp:1009:2:1009:9 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:981:6:981:8 | arr | array |
108-
| tests.cpp:1028:2:1028:7 | call to memset | This 'memset' operation accesses 120 bytes but the $@ is only 40 bytes. | tests.cpp:1020:12:1020:15 | arr1 | destination buffer |
109-
| tests.cpp:1031:2:1031:7 | call to memset | This 'memset' operation accesses 130 bytes but the $@ is only 40 bytes. | tests.cpp:1020:12:1020:15 | arr1 | destination buffer |
90+
| tests.cpp:1031:2:1031:7 | call to memset | This 'memset' operation accesses 130 bytes but the $@ is only 120 bytes. | tests.cpp:1020:12:1020:15 | arr1 | destination buffer |
11091
| tests_restrict.c:12:2:12:7 | call to memcpy | This 'memcpy' operation accesses 2 bytes but the $@ is only 1 byte. | tests_restrict.c:7:6:7:13 | smallbuf | source buffer |
11192
| unions.cpp:26:2:26:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:21:10:21:11 | mu | destination buffer |
11293
| unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
@@ -115,5 +96,4 @@
11596
| var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'strncpy' operation may access 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
11697
| var_size_struct.cpp:87:3:87:19 | access to array | This array indexing operation accesses byte offset 67 but the $@ is only 64 bytes. | var_size_struct.cpp:78:7:78:14 | elements | array |
11798
| var_size_struct.cpp:99:3:99:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
118-
| var_size_struct.cpp:101:3:101:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
11999
| var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'strncpy' operation may access 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowStatic.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,4 @@
55
| tests.cpp:245:42:245:42 | 6 | Potential buffer-overflow: 'global_array_5' has size 5 not 6. |
66
| tests.cpp:351:2:351:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. |
77
| tests.cpp:352:17:352:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. |
8-
| tests.cpp:927:2:927:16 | access to array | Potential buffer-overflow: 'cs' has size 4 but 'cs[4]' may be accessed here. |
9-
| tests.cpp:928:2:928:17 | access to array | Potential buffer-overflow: 'cs' has size 4 but 'cs[39]' may be accessed here. |
10-
| tests.cpp:929:2:929:17 | access to array | Potential buffer-overflow: 'cs' has size 4 but 'cs[40]' may be accessed here. |
11-
| tests.cpp:932:2:932:16 | access to array | Potential buffer-overflow: 'cs' has size 4 but 'cs[4]' may be accessed here. |
128
| var_size_struct.cpp:103:39:103:41 | 129 | Potential buffer-overflow: 'str' has size 128 not 129. |

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/tests.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ void test12()
309309
memset(&myVar, 0, sizeof(myVar)); // GOOD
310310
memset(&myVar, 0, sizeof(myVar) + 1); // BAD: overrun write of myVar
311311
memset(myVar.buffer, 0, 16); // GOOD
312-
memset(myVar.buffer, 0, 17); // BAD: overrun write of myVar.buffer
312+
memset(myVar.buffer, 0, 17); // DUBIOUS: overrun write of myVar.buffer, but not out of myVar itself [NOT DETECTED]
313313
memset(&(myVar.field), 0, sizeof(int)); // GOOD
314314
memset(&(myVar.field), 0, sizeof(int) * 2); // BAD: overrun write of myVar.field
315315

@@ -912,33 +912,33 @@ void test26() {
912912

913913
maa.bs[0].as[-1] = 0; // BAD: underrun write [NOT DETECTED]
914914
maa.bs[0].as[0] = 0; // GOOD
915-
maa.bs[0].as[99] = 0; // GOOD (overflows into bs[9]) [FALSE POSITIVE]
916-
maa.bs[0].as[100] = 0; // BAD: overrun write
917-
maa.bs[1].as[-1] = 0; // GOOD (underflows into bs[0]) [FALSE POSITIVE]
915+
maa.bs[0].as[99] = 0; // GOOD (overflows into bs[9])
916+
maa.bs[0].as[100] = 0; // BAD: overrun write [NOT DETECTED]
917+
maa.bs[1].as[-1] = 0; // GOOD (underflows into bs[0])
918918
maa.bs[1].as[0] = 0; // GOOD
919-
maa.bs[1].as[99] = 0; // BAD: overrun write
920-
maa.bs[1].as[100] = 0; // BAD: overrun write
919+
maa.bs[1].as[99] = 0; // BAD: overrun write [NOT DETECTED]
920+
maa.bs[1].as[100] = 0; // BAD: overrun write[ NOT DETECTED]
921921

922922
maa.ds[0].i = 0; // GOOD
923923
maa.ds[9].i = 0; // GOOD
924-
maa.ds[10].i = 0; // BAD: overrun write
924+
maa.ds[10].i = 0; // BAD: overrun write [NOT DETECTED]
925925
maa.ds[0].cs[0] = 0; // GOOD
926926
maa.ds[0].cs[3] = 0; // GOOD
927-
maa.ds[0].cs[4] = 0; // GOOD (overflows into vs[1] [FALSE POSITIVE]
928-
maa.ds[0].cs[39] = 0; // GOOD (overflows into vs[9] [FALSE POSITIVE]
929-
maa.ds[0].cs[40] = 0; // BAD: overrun write
927+
maa.ds[0].cs[4] = 0; // GOOD (overflows into vs[1])
928+
maa.ds[0].cs[39] = 0; // GOOD (overflows into vs[9])
929+
maa.ds[0].cs[40] = 0; // BAD: overrun write [NOT DETECTED]
930930
maa.ds[9].cs[0] = 0; // GOOD
931931
maa.ds[9].cs[3] = 0; // GOOD
932-
maa.ds[9].cs[4] = 0; // BAD: overrun write
932+
maa.ds[9].cs[4] = 0; // BAD: overrun write [NOT DETECTED]
933933

934-
maa.ys[0].xs[-1] = 0; // BAD: underrun write
934+
maa.ys[0].xs[-1] = 0; // BAD: underrun write [NOT DETECTED]
935935
maa.ys[0].xs[0] = 0; // GOOD
936-
maa.ys[0].xs[99] = 0; // GOOD (overflows into bs[9]) [FALSE POSITIVE]
937-
maa.ys[0].xs[100] = 0; // BAD: overrun write
938-
maa.ys[1].xs[-1] = 0; // GOOD (underflows into ys[0]) [FALSE POSITIVE]
936+
maa.ys[0].xs[99] = 0; // GOOD (overflows into bs[9])
937+
maa.ys[0].xs[100] = 0; // BAD: overrun write [NOT DETECTED]
938+
maa.ys[1].xs[-1] = 0; // GOOD (underflows into ys[0])
939939
maa.ys[1].xs[0] = 0; // GOOD
940-
maa.ys[1].xs[99] = 0; // BAD: overrun write
941-
maa.ys[1].xs[100] = 0; // BAD: overrun write
940+
maa.ys[1].xs[99] = 0; // BAD: overrun write [NOT DETECTED]
941+
maa.ys[1].xs[100] = 0; // BAD: overrun write [NOT DETECTED]
942942

943943
char zs[2][2];
944944
zs[0][-1] = 0; // BAD: underrun write [NOT DETECTED]
@@ -1025,7 +1025,7 @@ typedef _myStruct29 myStruct29;
10251025
void test29() {
10261026
myStruct29 *ptr;
10271027

1028-
memset(ptr->arr1, 0, sizeof(ptr->arr1) + sizeof(ptr->arr2)); // GOOD (overwrites arr1, arr2) [FALSE POSITIVE]
1028+
memset(ptr->arr1, 0, sizeof(ptr->arr1) + sizeof(ptr->arr2)); // GOOD (overwrites arr1, arr2)
10291029
memset(&(ptr->arr1[0]), 0, sizeof(ptr->arr1) + sizeof(ptr->arr2)); // GOOD (overwrites arr1, arr2)
10301030

10311031
memset(ptr->arr1, 0, sizeof(ptr->arr1) + sizeof(ptr->arr2) + 10); // BAD

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ void testNotVarStruct1() {
9696
notVarStruct1 *nvs1 = (notVarStruct1 *)malloc(sizeof(notVarStruct1) * 2);
9797

9898
memset(nvs1->str, 0, 128); // GOOD
99-
memset(nvs1->str, 0, 129); // BAD: buffer overflow
99+
memset(nvs1->str, 0, 129); // DUBIOUS: buffer overflow (overflows nvs1->str but not nvs1 overall)
100100
memset(nvs1[1].str, 0, 128); // GOOD
101-
memset(nvs1[1].str, 0, 129); // BAD: buffer overflow
101+
memset(nvs1[1].str, 0, 129); // BAD: buffer overflow [NOT DETECTED]
102102
strncpy(nvs1->str, "Hello, world!", 128); // GOOD
103103
strncpy(nvs1->str, "Hello, world!", 129); // BAD
104104
}

0 commit comments

Comments
 (0)