Skip to content

Commit df7a4ac

Browse files
author
Robert Marsh
authored
Merge pull request #11722 from MathiasVP/make-buffer.qll-unique-again
C++: Use `unique` in `getBufferSize`
2 parents c09ed10 + 81de93d commit df7a4ac

4 files changed

Lines changed: 31 additions & 68 deletions

File tree

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

Lines changed: 21 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -73,67 +73,29 @@ private int isSource(Expr bufferExpr, Element why) {
7373
)
7474
}
7575

76-
/**
77-
* Holds if `e2` is an expression that is derived from `e1` such that if `e1[n]` is a
78-
* well-defined expression for some number `n`, then `e2[n + delta]` is also a well-defined
79-
* expression.
80-
*/
81-
private predicate step(Expr e1, Expr e2, int delta) {
82-
getBufferSizeCand0(e1) and
83-
(
84-
exists(Variable bufferVar, Class parentClass, VariableAccess parentPtr, int bufferSize |
85-
e1 = parentPtr
86-
|
87-
bufferVar = e2.(VariableAccess).getTarget() and
88-
// buffer is the parentPtr->bufferVar of a 'variable size struct'
89-
memberMayBeVarSize(parentClass, bufferVar) and
90-
parentPtr = e2.(VariableAccess).getQualifier() and
91-
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
92-
(
93-
if exists(bufferVar.getType().getSize())
94-
then bufferSize = bufferVar.getType().getSize()
95-
else bufferSize = 0
96-
) and
97-
delta = bufferSize - parentClass.getSize()
98-
)
99-
or
100-
DataFlow::localExprFlowStep(e1, e2) and
101-
delta = 0
102-
)
103-
}
104-
105-
pragma[nomagic]
106-
private predicate getBufferSizeCand0(Expr e) {
107-
exists(isSource(e, _))
108-
or
109-
exists(Expr e0 |
110-
getBufferSizeCand0(e0) and
111-
step(e0, e, _)
112-
)
113-
}
114-
115-
/**
116-
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
117-
*
118-
* NOTE: There can be multiple `(result, why)` for a given `bufferExpr`.
119-
*/
120-
private int getBufferSizeCand(Expr bufferExpr, Element why) {
121-
getBufferSizeCand0(bufferExpr) and
122-
(
123-
result = isSource(bufferExpr, why)
124-
or
125-
exists(Expr e0, int delta, int size |
126-
size = getBufferSizeCand(e0, why) and
127-
step(e0, bufferExpr, delta) and
128-
result = size + delta
129-
)
130-
)
131-
}
132-
13376
/**
13477
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
13578
*/
79+
language[monotonicAggregates]
13680
int getBufferSize(Expr bufferExpr, Element why) {
137-
result = max( | | getBufferSizeCand(bufferExpr, _)) and
138-
result = getBufferSizeCand(bufferExpr, why)
81+
result = isSource(bufferExpr, why)
82+
or
83+
exists(Class parentClass, VariableAccess parentPtr, int bufferSize, Variable bufferVar |
84+
bufferVar = bufferExpr.(VariableAccess).getTarget() and
85+
// buffer is the parentPtr->bufferVar of a 'variable size struct'
86+
memberMayBeVarSize(parentClass, bufferVar) and
87+
why = bufferVar and
88+
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
89+
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
90+
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
91+
|
92+
if exists(bufferVar.getType().getSize())
93+
then bufferSize = bufferVar.getType().getSize()
94+
else bufferSize = 0
95+
)
96+
or
97+
// dataflow (all sources must be the same size)
98+
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
99+
// find reason
100+
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
139101
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,25 @@
4242
| tests.cpp:476:2:476:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
4343
| tests.cpp:477:2:477:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
4444
| tests.cpp:481:2:481:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
45-
| tests.cpp:485:2:485:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
4645
| tests.cpp:487:2:487:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:473:21:473:26 | call to malloc | array |
4746
| tests.cpp:491:2:491:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:474:21:474:26 | call to malloc | array |
48-
| tests.cpp:495:2:495:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:474:21:474:26 | call to malloc | array |
4947
| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:502:15:502:20 | call to malloc | destination buffer |
5048
| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:510:16:510:21 | call to malloc | destination buffer |
5149
| tests.cpp:541:6:541:10 | call to fread | This 'fread' operation may access 101 bytes but the $@ is only 100 bytes. | tests.cpp:532:7:532:16 | charBuffer | destination buffer |
5250
| tests.cpp:546:6:546:10 | call to fread | This 'fread' operation may access 400 bytes but the $@ is only 100 bytes. | tests.cpp:532:7:532:16 | charBuffer | destination buffer |
5351
| tests.cpp:569:6:569:15 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array |
5452
| tests.cpp:577:7:577:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array |
55-
| tests.cpp:579:6:579:12 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array |
5653
| tests.cpp:586:6:586:12 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:565:7:565:12 | buffer | array |
5754
| 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 |
5855
| 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 |
56+
| unions.cpp:27:2:27:7 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 10 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
57+
| unions.cpp:29:2:29:7 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 10 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
58+
| unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 10 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
5959
| 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 |
6060
| unions.cpp:34:2:34:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:16:7:16:11 | large | destination buffer |
61-
| var_size_struct.cpp:71:3:71:8 | call to memset | This 'memset' operation accesses 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:67:35:67:40 | call to malloc | destination buffer |
62-
| 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:67:35:67:40 | call to malloc | destination buffer |
63-
| 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:82:35:82:40 | call to malloc | array |
61+
| var_size_struct.cpp:71:3:71:8 | call to memset | This 'memset' operation accesses 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
62+
| 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 |
63+
| 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 |
6464
| 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 |
6565
| 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 |
6666
| 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/tests.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ void test18()
482482
while (*p3 != 0) {
483483
p3 = update(p3);
484484
}
485-
p3[-1] = 0; // GOOD [FALSE POSITIVE]
485+
p3[-1] = 0; // GOOD
486486

487487
p4[-1] = 0; // BAD: underrun write
488488
p4++;
@@ -492,7 +492,7 @@ void test18()
492492
while (*p5 != 0) {
493493
p5 = update(p5);
494494
}
495-
p5[-1] = 0; // GOOD [FALSE POSITIVE]
495+
p5[-1] = 0; // GOOD
496496
}
497497

498498
void test19(bool b)
@@ -576,7 +576,7 @@ void test21(bool cond)
576576
} else {
577577
if (ptr[-1] == 0) { return; } // BAD: accesses buffer[-1]
578578
}
579-
if (ptr[-1] == 0) { return; } // BAD: accesses buffer[-1] or buffer[0]
579+
if (ptr[-1] == 0) { return; } // BAD: accesses buffer[-1] or buffer[0] [NOT DETECTED]
580580

581581
ptr = buffer;
582582
for (i = 0; i < 2; i++)

cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/VeryLikelyOverrunWrite.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
| tests.c:186:3:186:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 2 bytes. |
1818
| tests.c:189:3:189:9 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
1919
| unions.c:26:2:26:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. |
20+
| unions.c:27:2:27:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 15 bytes. |
2021
| unions.c:27:2:27:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. |
2122
| var_size_struct.cpp:22:3:22:8 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 9 bytes. |

0 commit comments

Comments
 (0)