Skip to content

Commit 4762e88

Browse files
committed
C++: Add inline expectations tests for the invalid-pointer-to-dereference stage of the query.
1 parent a735d18 commit 4762e88

File tree

3 files changed

+117
-34
lines changed

3 files changed

+117
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
failures
2+
testFailures
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import cpp
2+
import semmle.code.cpp.security.InvalidPointerDereference.InvalidPointerToDereference
3+
import TestUtilities.InlineExpectationsTest
4+
import semmle.code.cpp.ir.IR
5+
import semmle.code.cpp.dataflow.new.DataFlow
6+
7+
string case3(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
8+
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
9+
not exists(case2(_, _, operation)) and
10+
not exists(case1(_, _, operation)) and
11+
exists(int derefSourceLine, int derefSinkLine, int operationLine |
12+
derefSourceLine = derefSource.getLocation().getStartLine() and
13+
derefSinkLine = derefSink.getLocation().getStartLine() and
14+
operationLine = operation.getLocation().getStartLine() and
15+
derefSourceLine != derefSinkLine and
16+
derefSinkLine != operationLine and
17+
result = "L" + derefSourceLine + "->L" + derefSinkLine + "->L" + operationLine
18+
)
19+
}
20+
21+
string case2(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
22+
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
23+
not exists(case1(_, _, operation)) and
24+
exists(int derefSourceLine, int derefSinkLine, int operationLine |
25+
derefSourceLine = derefSource.getLocation().getStartLine() and
26+
derefSinkLine = derefSink.getLocation().getStartLine() and
27+
operationLine = operation.getLocation().getStartLine() and
28+
derefSourceLine = derefSinkLine and
29+
derefSinkLine != operationLine and
30+
result = "L" + derefSourceLine + "->L" + operationLine
31+
)
32+
}
33+
34+
string case1(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
35+
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
36+
exists(int derefSourceLine, int derefSinkLine, int operationLine |
37+
derefSourceLine = derefSource.getLocation().getStartLine() and
38+
derefSinkLine = derefSink.getLocation().getStartLine() and
39+
operationLine = operation.getLocation().getStartLine() and
40+
derefSourceLine = derefSinkLine and
41+
derefSinkLine = operationLine and
42+
result = "L" + derefSourceLine
43+
)
44+
}
45+
46+
module InvalidPointerToDereferenceTest implements TestSig {
47+
string getARelevantTag() { result = "deref" }
48+
49+
predicate hasActualResult(Location location, string element, string tag, string value) {
50+
exists(
51+
PointerArithmeticInstruction pai, DataFlow::Node derefSource, DataFlow::Node derefSink,
52+
DataFlow::Node operation, int delta, string value1, string value2
53+
|
54+
operationIsOffBy(_, pai, derefSource, derefSink, _, operation, delta) and
55+
location = operation.getLocation() and
56+
element = operation.toString() and
57+
tag = "deref" and
58+
value = value1 + value2
59+
|
60+
(
61+
value1 = case3(derefSource, derefSink, operation)
62+
or
63+
value1 = case2(derefSource, derefSink, operation)
64+
or
65+
value1 = case1(derefSource, derefSink, operation)
66+
) and
67+
(
68+
delta > 0 and
69+
value2 = "+" + delta
70+
or
71+
delta = 0 and
72+
value2 = ""
73+
or
74+
delta < 0 and
75+
value2 = "-" + (-delta)
76+
)
77+
)
78+
}
79+
}
80+
81+
import MakeTest<InvalidPointerToDereferenceTest>

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ char *malloc(int size);
33
void test1(int size) {
44
char* p = malloc(size);
55
char* q = p + size; // $ alloc=L4
6-
char a = *q; // BAD
6+
char a = *q; // $ deref=L6 // BAD
77
char b = *(q - 1); // GOOD
8-
char c = *(q + 1); // BAD
8+
char c = *(q + 1); // $ deref=L8+1 // BAD
99
char d = *(q + size); // BAD [NOT DETECTED]
1010
char e = *(q - size); // GOOD
1111
char f = *(q + size + 1); // BAD [NOT DETECTED]
@@ -17,7 +17,7 @@ void test2(int size) {
1717
char* q = p + size - 1; // $ alloc=L16
1818
char a = *q; // GOOD
1919
char b = *(q - 1); // GOOD
20-
char c = *(q + 1); // BAD
20+
char c = *(q + 1); // $ deref=L20 // BAD
2121
char d = *(q + size); // BAD [NOT DETECTED]
2222
char e = *(q - size); // GOOD
2323
char f = *(q + size + 1); // BAD [NOT DETECTED]
@@ -27,9 +27,9 @@ void test2(int size) {
2727
void test3(int size) {
2828
char* p = malloc(size + 1);
2929
char* q = p + (size + 1); // $ alloc=L28+1
30-
char a = *q; // BAD
30+
char a = *q; // $ deref=L30 // BAD
3131
char b = *(q - 1); // GOOD
32-
char c = *(q + 1); // BAD
32+
char c = *(q + 1); // $ deref=L32+1 // BAD
3333
char d = *(q + size); // BAD [NOT DETECTED]
3434
char e = *(q - size); // GOOD
3535
char f = *(q + size + 1); // BAD [NOT DETECTED]
@@ -39,9 +39,9 @@ void test3(int size) {
3939
void test4(int size) {
4040
char* p = malloc(size - 1);
4141
char* q = p + (size - 1); // $ alloc=L40-1
42-
char a = *q; // BAD
42+
char a = *q; // $ deref=L42 // BAD
4343
char b = *(q - 1); // GOOD
44-
char c = *(q + 1); // BAD
44+
char c = *(q + 1); // $ deref=L44+1 // BAD
4545
char d = *(q + size); // BAD [NOT DETECTED]
4646
char e = *(q - size); // GOOD
4747
char f = *(q + size + 1); // BAD [NOT DETECTED]
@@ -64,7 +64,7 @@ void test5(int size) {
6464
}
6565

6666
for (char* p = begin; p <= end; ++p) {
67-
*p = 0; // BAD
67+
*p = 0; // $ deref=L53->L62->L67 deref=L53->L66->L67 // BAD
6868
}
6969

7070
for (char* p = begin; p < end; ++p) {
@@ -93,7 +93,7 @@ void test6(int size) {
9393
}
9494

9595
for (char* p = arr.begin; p <= arr.end; ++p) {
96-
*p = 0; // BAD
96+
*p = 0; // $ deref=L83->L91->L96 deref=L83->L95->L96 // BAD
9797
}
9898

9999
for (char* p = arr.begin; p < arr.end; ++p) {
@@ -107,7 +107,7 @@ void test7_callee(array_t arr) {
107107
}
108108

109109
for (char* p = arr.begin; p <= arr.end; ++p) {
110-
*p = 0; // BAD
110+
*p = 0; // $ deref=L83->L105->L110 deref=L83->L109->L110 // BAD
111111
}
112112

113113
for (char* p = arr.begin; p < arr.end; ++p) {
@@ -154,7 +154,7 @@ void test9(int size) {
154154
}
155155

156156
for (char* p = arr->begin; p <= arr->end; ++p) {
157-
*p = 0; // BAD
157+
*p = 0; // $ deref=L144->L156->L157 // BAD
158158
}
159159

160160
for (char* p = arr->begin; p < arr->end; ++p) {
@@ -168,7 +168,7 @@ void test10_callee(array_t *arr) {
168168
}
169169

170170
for (char* p = arr->begin; p <= arr->end; ++p) {
171-
*p = 0; // BAD
171+
*p = 0; // $ deref=L144->L166->L171 deref=L144->L170->L171 // BAD
172172
}
173173

174174
for (char* p = arr->begin; p < arr->end; ++p) {
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
198198
return;
199199
}
200200

201-
p[index] = '\0'; // BAD
201+
p[index] = '\0'; // $ deref=L201 // BAD
202202
}
203203

204204
void test13(unsigned len, unsigned index) {
@@ -210,7 +210,7 @@ void test13(unsigned len, unsigned index) {
210210
return;
211211
}
212212

213-
*q = '\0'; // BAD
213+
*q = '\0'; // $ deref=L213 // BAD
214214
}
215215

216216
bool unknown();
@@ -229,14 +229,14 @@ void test15(unsigned index) {
229229
return;
230230
}
231231
int* newname = new int[size];
232-
newname[index] = 0; // $ alloc=L231 // GOOD [FALSE POSITIVE]
232+
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE]
233233
}
234234

235235
void test16(unsigned index) {
236236
unsigned size = index + 13;
237237
if(size >= index) {
238238
int* newname = new int[size];
239-
newname[index] = 0; // $ alloc=L238 // GOOD [FALSE POSITIVE]
239+
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE]
240240
}
241241
}
242242

@@ -251,7 +251,7 @@ void test17(unsigned *p, unsigned x, unsigned k) {
251251
// The following access is okay because:
252252
// n = 3*p[0] + k >= p[0] + k >= p[1] + k > p[1] = i
253253
// (where p[0] denotes the original value for p[0])
254-
p[i] = x; // $ alloc=L248 // GOOD [FALSE POSITIVE]
254+
p[i] = x; // $ alloc=L248 deref=L254 // GOOD [FALSE POSITIVE]
255255
}
256256
}
257257

@@ -261,7 +261,7 @@ void test17(unsigned len)
261261
int *end = xs + len; // $ alloc=L260
262262
for (int *x = xs; x <= end; x++)
263263
{
264-
int i = *x; // BAD
264+
int i = *x; // $ deref=L264 // BAD
265265
}
266266
}
267267

@@ -271,7 +271,7 @@ void test18(unsigned len)
271271
int *end = xs + len; // $ alloc=L270
272272
for (int *x = xs; x <= end; x++)
273273
{
274-
*x = 0; // BAD
274+
*x = 0; // $ deref=L274 // BAD
275275
}
276276
}
277277

@@ -305,7 +305,7 @@ void test21() {
305305

306306
for (int i = 0; i < n; i += 2) {
307307
xs[i] = test21_get(i); // GOOD
308-
xs[i+1] = test21_get(i+1); // $ alloc=L304 alloc=L304-1 // GOOD [FALSE POSITIVE]
308+
xs[i+1] = test21_get(i+1); // $ alloc=L304 alloc=L304-1 deref=L308 // GOOD [FALSE POSITIVE]
309309
}
310310
}
311311

@@ -355,8 +355,8 @@ void test25(unsigned size) {
355355
char *xs = new char[size];
356356
char *end = xs + size; // $ alloc=L355
357357
char *end_plus_one = end + 1;
358-
int val1 = *end_plus_one; // BAD
359-
int val2 = *(end_plus_one + 1); // BAD
358+
int val1 = *end_plus_one; // $ deref=L358+1 // BAD
359+
int val2 = *(end_plus_one + 1); // $ deref=L359+2 // BAD
360360
}
361361

362362
void test26(unsigned size) {
@@ -381,7 +381,7 @@ void test27(unsigned size, bool b) {
381381
end++;
382382
}
383383

384-
int val = *end; // BAD
384+
int val = *end; // $ deref=L384+1 // BAD
385385
}
386386

387387
void test28(unsigned size) {
@@ -412,7 +412,7 @@ void test28_simple2(unsigned size) {
412412
if (xs < end) {
413413
xs++;
414414
if (xs < end + 1) {
415-
xs[0] = 0; // BAD
415+
xs[0] = 0; // $ deref=L415 // BAD
416416
}
417417
}
418418
}
@@ -423,7 +423,7 @@ void test28_simple3(unsigned size) {
423423
if (xs < end) {
424424
xs++;
425425
if (xs - 1 < end) {
426-
xs[0] = 0; // BAD
426+
xs[0] = 0; // $ deref=L426 // BAD
427427
}
428428
}
429429
}
@@ -435,7 +435,7 @@ void test28_simple4(unsigned size) {
435435
end++;
436436
xs++;
437437
if (xs < end) {
438-
xs[0] = 0; // BAD
438+
xs[0] = 0; // $ deref=L438 // BAD
439439
}
440440
}
441441
}
@@ -447,7 +447,7 @@ void test28_simple5(unsigned size) {
447447
if (xs < end) {
448448
xs++;
449449
if (xs < end) {
450-
xs[0] = 0; // BAD
450+
xs[0] = 0; // $ deref=L450 // BAD
451451
}
452452
}
453453
}
@@ -483,7 +483,7 @@ void test28_simple8(unsigned size) {
483483
if (xs < end) {
484484
xs++;
485485
if (xs < end - 1) {
486-
xs[0] = 0; // BAD
486+
xs[0] = 0; // $ deref=L486+498 // BAD
487487
}
488488
}
489489
}
@@ -545,7 +545,7 @@ void test31_simple2(unsigned size, unsigned src_pos)
545545
src_pos = size;
546546
}
547547
if (src_pos < size + 1) {
548-
xs[src_pos] = 0; // $ alloc=L543 // BAD
548+
xs[src_pos] = 0; // $ alloc=L543 deref=L548 // BAD
549549
}
550550
}
551551

@@ -556,7 +556,7 @@ void test31_simple3(unsigned size, unsigned src_pos)
556556
src_pos = size;
557557
}
558558
if (src_pos - 1 < size) {
559-
xs[src_pos] = 0; // $ alloc=L554 // BAD
559+
xs[src_pos] = 0; // $ alloc=L554 deref=L559 // BAD
560560
}
561561
}
562562

@@ -644,7 +644,7 @@ void test31_simple1_sub1(unsigned size, unsigned src_pos)
644644
src_pos = size;
645645
}
646646
if (src_pos < size) {
647-
xs[src_pos] = 0; // $ alloc=L642-1 // BAD
647+
xs[src_pos] = 0; // $ alloc=L642-1 deref=L647 // BAD
648648
}
649649
}
650650

@@ -659,7 +659,7 @@ void test32(unsigned size) {
659659
xs++;
660660
if (xs >= end)
661661
return;
662-
xs[0] = 0; // GOOD [FALSE POSITIVE]
662+
xs[0] = 0; // $ deref=L656->L662+1 deref=L657->L662+1 GOOD [FALSE POSITIVE]
663663
}
664664

665665
void test33(unsigned size, unsigned src_pos)
@@ -672,7 +672,7 @@ void test33(unsigned size, unsigned src_pos)
672672
while (dst_pos < size - 1) {
673673
dst_pos++;
674674
if (true)
675-
xs[dst_pos++] = 0; // $ alloc=L667+1 // GOOD [FALSE POSITIVE]
675+
xs[dst_pos++] = 0; // $ alloc=L667+1 deref=L675 // GOOD [FALSE POSITIVE]
676676
}
677677
}
678678

@@ -688,5 +688,5 @@ void test_missing_call_context_1(unsigned size) {
688688
void test_missing_call_context_2(unsigned size) {
689689
int* p = new int[size];
690690
int* end_minus_one = pointer_arithmetic(p, size - 1);
691-
*end_minus_one = '0'; // GOOD
691+
*end_minus_one = '0'; // $ deref=L680->L690->L691 // GOOD
692692
}

0 commit comments

Comments
 (0)