Skip to content

Commit 2577540

Browse files
authored
[NFC][analyzer] OOB test consolidation II: constraint checking (#126748)
This commit heavily refactors `out-of-bounds-constraint-check.c`: 1. The complex combinations of several `clang_analyzer_eval` calls were replaced by `clang_analyzer_value`, which can directly query the range of a symbol. 2. Testcases were renamed to a (hopefully) more consistent scheme. 3. The use of `size_t` as an argument type was replaced by `unsigned long long`, which is usually a no-op, but seems to be a better choice if I look for `64u` in the output of `clang_analyzer_value`. 4. The single "dynamic extent" case was generalized into a full set of tests that use `malloc`. 5. Half of the testcases (the ones that don't use `malloc`) were changed to use an `int[5]` array instead of a string literal. After this change the tests in this file cover every functionality that was tested by the testcases `test_assume_after_access{,2}` in the file `out-of-bounds.c` so I was able to delete those two testcases (and therefore consolidate the validation of these constraints within a single test file). This is the second commit in a series that reorganizes the tests of `security.ArrayBound` to system that's easier to understand and maintain. (Note that this file wasn't significantly modified by the recent commit 6e17ed9 which renamed `alpha.security.ArrayBoundV2` to `security.ArrayBound`; but I still felt that this cleanup may be useful.)
1 parent 3453444 commit 2577540

File tree

2 files changed

+156
-119
lines changed

2 files changed

+156
-119
lines changed
Lines changed: 155 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,163 @@
11
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,security.ArrayBound,debug.ExprInspection \
22
// RUN: -analyzer-config eagerly-assume=false -verify %s
33

4-
void clang_analyzer_eval(int);
5-
void clang_analyzer_printState(void);
6-
7-
typedef typeof(sizeof(int)) size_t;
8-
const char a[] = "abcd"; // extent: 5 bytes
9-
10-
void symbolic_size_t_and_int0(size_t len) {
11-
(void)a[len + 1]; // no-warning
12-
// We infered that the 'len' must be in a specific range to make the previous indexing valid.
13-
// len: [0,3]
14-
clang_analyzer_eval(len <= 3); // expected-warning {{TRUE}}
15-
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
16-
}
17-
18-
void symbolic_size_t_and_int1(size_t len) {
19-
(void)a[len]; // no-warning
20-
// len: [0,4]
21-
clang_analyzer_eval(len <= 4); // expected-warning {{TRUE}}
22-
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
23-
}
24-
25-
void symbolic_size_t_and_int2(size_t len) {
26-
(void)a[len - 1]; // no-warning
27-
// len: [1,5]
28-
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
29-
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
30-
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
31-
}
32-
33-
void symbolic_uint_and_int0(unsigned len) {
34-
(void)a[len + 1]; // no-warning
35-
// len: [0,3]
36-
clang_analyzer_eval(0 <= len && len <= 3); // expected-warning {{TRUE}}
37-
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
38-
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
39-
}
40-
41-
void symbolic_uint_and_int1(unsigned len) {
42-
(void)a[len]; // no-warning
43-
// len: [0,4]
44-
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
45-
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
46-
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
47-
}
48-
void symbolic_uint_and_int2(unsigned len) {
49-
(void)a[len - 1]; // no-warning
50-
// len: [1,5]
51-
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
52-
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
53-
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
54-
}
55-
56-
void symbolic_int_and_int0(int len) {
57-
(void)a[len + 1]; // no-warning
58-
// len: [-1,3]
59-
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
60-
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
61-
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
62-
}
63-
void symbolic_int_and_int1(int len) {
64-
(void)a[len]; // no-warning
65-
// len: [0,4]
66-
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
67-
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
68-
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
69-
}
70-
void symbolic_int_and_int2(int len) {
71-
(void)a[len - 1]; // no-warning
72-
// len: [1,5]
73-
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
74-
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
75-
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
76-
}
77-
78-
void symbolic_longlong_and_int0(long long len) {
79-
(void)a[len + 1]; // no-warning
80-
// len: [-1,3]
81-
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
82-
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
83-
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
4+
// When the checker security.ArrayBound encounters an array subscript operation
5+
// that _may be_ in bounds, it assumes that indexing _is_ in bound. This test
6+
// file validates these assumptions.
7+
8+
void clang_analyzer_value(int);
9+
10+
// Simple case: memory area with a static extent.
11+
12+
extern int FiveInts[5];
13+
14+
void int_plus_one(int len) {
15+
(void)FiveInts[len + 1]; // no-warning
16+
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
17+
}
18+
19+
void int_neutral(int len) {
20+
(void)FiveInts[len]; // no-warning
21+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
22+
}
23+
24+
void int_minus_one(int len) {
25+
(void)FiveInts[len - 1]; // no-warning
26+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
27+
}
28+
29+
void unsigned_plus_one(unsigned len) {
30+
(void)FiveInts[len + 1]; // no-warning
31+
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
32+
}
33+
34+
void unsigned_neutral(unsigned len) {
35+
(void)FiveInts[len]; // no-warning
36+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
37+
}
38+
39+
void unsigned_minus_one(unsigned len) {
40+
(void)FiveInts[len - 1]; // no-warning
41+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
42+
}
43+
44+
void ll_plus_one(long long len) {
45+
(void)FiveInts[len + 1]; // no-warning
46+
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
47+
}
48+
49+
void ll_neutral(long long len) {
50+
(void)FiveInts[len]; // no-warning
51+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
52+
}
53+
54+
void ll_minus_one(long long len) {
55+
(void)FiveInts[len - 1]; // no-warning
56+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
57+
}
58+
59+
void ull_plus_one(unsigned long long len) {
60+
(void)FiveInts[len + 1]; // no-warning
61+
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
62+
}
63+
64+
void ull_neutral(unsigned long long len) {
65+
(void)FiveInts[len]; // no-warning
66+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
67+
}
68+
69+
void ull_minus_one(unsigned long long len) {
70+
(void)FiveInts[len - 1]; // no-warning
71+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
8472
}
8573

74+
// Also try the same with a dynamically allocated memory block, because in the
75+
// past there were issues with the type/signedness of dynamic extent symbols.
76+
77+
typedef __typeof(sizeof(int)) size_t;
8678
void *malloc(size_t);
8779
void free(void *);
88-
void symbolic_longlong_and_int0_dynamic_extent(long long len) {
89-
char *b = malloc(5);
90-
(void)b[len + 1]; // no-warning
91-
// len: [-1,3]
92-
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
93-
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
94-
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
95-
free(b);
96-
}
97-
98-
void symbolic_longlong_and_int1(long long len) {
99-
(void)a[len]; // no-warning
100-
// len: [0,4]
101-
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
102-
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
103-
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
104-
}
105-
106-
void symbolic_longlong_and_int2(long long len) {
107-
(void)a[len - 1]; // no-warning
108-
// len: [1,5]
109-
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
110-
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
111-
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
80+
81+
void dyn_int_plus_one(int len) {
82+
char *p = malloc(5);
83+
p[len + 1] = 1; // no-warning
84+
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
85+
free(p);
86+
}
87+
88+
void dyn_int_neutral(int len) {
89+
char *p = malloc(5);
90+
p[len] = 1; // no-warning
91+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
92+
free(p);
93+
}
94+
95+
void dyn_int_minus_one(int len) {
96+
char *p = malloc(5);
97+
p[len - 1] = 1; // no-warning
98+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
99+
free(p);
100+
}
101+
102+
void dyn_unsigned_plus_one(unsigned len) {
103+
char *p = malloc(5);
104+
p[len + 1] = 1; // no-warning
105+
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
106+
free(p);
107+
}
108+
109+
void dyn_unsigned_neutral(unsigned len) {
110+
char *p = malloc(5);
111+
p[len] = 1; // no-warning
112+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
113+
free(p);
114+
}
115+
116+
void dyn_unsigned_minus_one(unsigned len) {
117+
char *p = malloc(5);
118+
p[len - 1] = 1; // no-warning
119+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
120+
free(p);
121+
}
122+
123+
void dyn_ll_plus_one(long long len) {
124+
char *p = malloc(5);
125+
p[len + 1] = 1; // no-warning
126+
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
127+
free(p);
128+
}
129+
130+
void dyn_ll_neutral(long long len) {
131+
char *p = malloc(5);
132+
p[len] = 1; // no-warning
133+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
134+
free(p);
135+
}
136+
137+
void dyn_ll_minus_one(long long len) {
138+
char *p = malloc(5);
139+
p[len - 1] = 1; // no-warning
140+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
141+
free(p);
142+
}
143+
144+
void dyn_ull_plus_one(unsigned long long len) {
145+
char *p = malloc(5);
146+
p[len + 1] = 1; // no-warning
147+
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
148+
free(p);
149+
}
150+
151+
void dyn_ull_neutral(unsigned long long len) {
152+
char *p = malloc(5);
153+
p[len] = 1; // no-warning
154+
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
155+
free(p);
156+
}
157+
158+
void dyn_ull_minus_one(unsigned long long len) {
159+
char *p = malloc(5);
160+
p[len - 1] = 1; // no-warning
161+
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
162+
free(p);
112163
}

clang/test/Analysis/out-of-bounds.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,security.ArrayBound,debug.ExprInspection -verify %s
2-
3-
void clang_analyzer_eval(int);
1+
// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,security.ArrayBound -verify %s
42

53
// Tests doing an out-of-bounds access after the end of an array using:
64
// - constant integer index
@@ -142,12 +140,6 @@ void test4(int x) {
142140
buf[x] = 1; // expected-warning{{Out of bound access to memory}}
143141
}
144142

145-
void test_assume_after_access(unsigned long x) {
146-
int buf[100];
147-
buf[x] = 1;
148-
clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
149-
}
150-
151143
// Don't warn when indexing below the start of a symbolic region's whose
152144
// base extent we don't know.
153145
int *get_symbolic(void);
@@ -180,12 +172,6 @@ void test_extern_void(void) {
180172
p[1] = 42; // no-warning
181173
}
182174

183-
void test_assume_after_access2(unsigned long x) {
184-
char buf[100];
185-
buf[x] = 1;
186-
clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
187-
}
188-
189175
struct incomplete;
190176
char test_comparison_with_extent_symbol(struct incomplete *p) {
191177
// Previously this was reported as a (false positive) overflow error because

0 commit comments

Comments
 (0)