mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 11:56:38 +00:00
[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 6e17ed9b04e5523cc910bf171c3122dcc64b86db which renamed `alpha.security.ArrayBoundV2` to `security.ArrayBound`; but I still felt that this cleanup may be useful.)
This commit is contained in:
parent
34534442a8
commit
257754011c
@ -1,112 +1,163 @@
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,security.ArrayBound,debug.ExprInspection \
|
||||
// RUN: -analyzer-config eagerly-assume=false -verify %s
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
void clang_analyzer_printState(void);
|
||||
// When the checker security.ArrayBound encounters an array subscript operation
|
||||
// that _may be_ in bounds, it assumes that indexing _is_ in bound. This test
|
||||
// file validates these assumptions.
|
||||
|
||||
typedef typeof(sizeof(int)) size_t;
|
||||
const char a[] = "abcd"; // extent: 5 bytes
|
||||
void clang_analyzer_value(int);
|
||||
|
||||
void symbolic_size_t_and_int0(size_t len) {
|
||||
(void)a[len + 1]; // no-warning
|
||||
// We infered that the 'len' must be in a specific range to make the previous indexing valid.
|
||||
// len: [0,3]
|
||||
clang_analyzer_eval(len <= 3); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
|
||||
// Simple case: memory area with a static extent.
|
||||
|
||||
extern int FiveInts[5];
|
||||
|
||||
void int_plus_one(int len) {
|
||||
(void)FiveInts[len + 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
|
||||
}
|
||||
|
||||
void symbolic_size_t_and_int1(size_t len) {
|
||||
(void)a[len]; // no-warning
|
||||
// len: [0,4]
|
||||
clang_analyzer_eval(len <= 4); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
|
||||
void int_neutral(int len) {
|
||||
(void)FiveInts[len]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
}
|
||||
|
||||
void symbolic_size_t_and_int2(size_t len) {
|
||||
(void)a[len - 1]; // no-warning
|
||||
// len: [1,5]
|
||||
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
|
||||
void int_minus_one(int len) {
|
||||
(void)FiveInts[len - 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
}
|
||||
|
||||
void symbolic_uint_and_int0(unsigned len) {
|
||||
(void)a[len + 1]; // no-warning
|
||||
// len: [0,3]
|
||||
clang_analyzer_eval(0 <= len && len <= 3); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
|
||||
void unsigned_plus_one(unsigned len) {
|
||||
(void)FiveInts[len + 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
|
||||
}
|
||||
|
||||
void symbolic_uint_and_int1(unsigned len) {
|
||||
(void)a[len]; // no-warning
|
||||
// len: [0,4]
|
||||
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
|
||||
}
|
||||
void symbolic_uint_and_int2(unsigned len) {
|
||||
(void)a[len - 1]; // no-warning
|
||||
// len: [1,5]
|
||||
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
|
||||
void unsigned_neutral(unsigned len) {
|
||||
(void)FiveInts[len]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
}
|
||||
|
||||
void symbolic_int_and_int0(int len) {
|
||||
(void)a[len + 1]; // no-warning
|
||||
// len: [-1,3]
|
||||
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
|
||||
}
|
||||
void symbolic_int_and_int1(int len) {
|
||||
(void)a[len]; // no-warning
|
||||
// len: [0,4]
|
||||
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
|
||||
}
|
||||
void symbolic_int_and_int2(int len) {
|
||||
(void)a[len - 1]; // no-warning
|
||||
// len: [1,5]
|
||||
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
|
||||
void unsigned_minus_one(unsigned len) {
|
||||
(void)FiveInts[len - 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
}
|
||||
|
||||
void symbolic_longlong_and_int0(long long len) {
|
||||
(void)a[len + 1]; // no-warning
|
||||
// len: [-1,3]
|
||||
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
|
||||
void ll_plus_one(long long len) {
|
||||
(void)FiveInts[len + 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
|
||||
}
|
||||
|
||||
void ll_neutral(long long len) {
|
||||
(void)FiveInts[len]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
}
|
||||
|
||||
void ll_minus_one(long long len) {
|
||||
(void)FiveInts[len - 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
}
|
||||
|
||||
void ull_plus_one(unsigned long long len) {
|
||||
(void)FiveInts[len + 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
|
||||
}
|
||||
|
||||
void ull_neutral(unsigned long long len) {
|
||||
(void)FiveInts[len]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
}
|
||||
|
||||
void ull_minus_one(unsigned long long len) {
|
||||
(void)FiveInts[len - 1]; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
}
|
||||
|
||||
// Also try the same with a dynamically allocated memory block, because in the
|
||||
// past there were issues with the type/signedness of dynamic extent symbols.
|
||||
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void *malloc(size_t);
|
||||
void free(void *);
|
||||
void symbolic_longlong_and_int0_dynamic_extent(long long len) {
|
||||
char *b = malloc(5);
|
||||
(void)b[len + 1]; // no-warning
|
||||
// len: [-1,3]
|
||||
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(0 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 2); // expected-warning {{UNKNOWN}}
|
||||
free(b);
|
||||
|
||||
void dyn_int_plus_one(int len) {
|
||||
char *p = malloc(5);
|
||||
p[len + 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void symbolic_longlong_and_int1(long long len) {
|
||||
(void)a[len]; // no-warning
|
||||
// len: [0,4]
|
||||
clang_analyzer_eval(0 <= len && len <= 4); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(1 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 3); // expected-warning {{UNKNOWN}}
|
||||
void dyn_int_neutral(int len) {
|
||||
char *p = malloc(5);
|
||||
p[len] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void symbolic_longlong_and_int2(long long len) {
|
||||
(void)a[len - 1]; // no-warning
|
||||
// len: [1,5]
|
||||
clang_analyzer_eval(1 <= len && len <= 5); // expected-warning {{TRUE}}
|
||||
clang_analyzer_eval(2 <= len); // expected-warning {{UNKNOWN}}
|
||||
clang_analyzer_eval(len <= 4); // expected-warning {{UNKNOWN}}
|
||||
void dyn_int_minus_one(int len) {
|
||||
char *p = malloc(5);
|
||||
p[len - 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_unsigned_plus_one(unsigned len) {
|
||||
char *p = malloc(5);
|
||||
p[len + 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_unsigned_neutral(unsigned len) {
|
||||
char *p = malloc(5);
|
||||
p[len] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_unsigned_minus_one(unsigned len) {
|
||||
char *p = malloc(5);
|
||||
p[len - 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ll_plus_one(long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len + 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [-1, 3] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ll_neutral(long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ll_minus_one(long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len - 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ull_plus_one(unsigned long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len + 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ull_neutral(unsigned long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
|
||||
free(p);
|
||||
}
|
||||
|
||||
void dyn_ull_minus_one(unsigned long long len) {
|
||||
char *p = malloc(5);
|
||||
p[len - 1] = 1; // no-warning
|
||||
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
|
||||
free(p);
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,security.ArrayBound,debug.ExprInspection -verify %s
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,security.ArrayBound -verify %s
|
||||
|
||||
// Tests doing an out-of-bounds access after the end of an array using:
|
||||
// - constant integer index
|
||||
@ -142,12 +140,6 @@ void test4(int x) {
|
||||
buf[x] = 1; // expected-warning{{Out of bound access to memory}}
|
||||
}
|
||||
|
||||
void test_assume_after_access(unsigned long x) {
|
||||
int buf[100];
|
||||
buf[x] = 1;
|
||||
clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
// Don't warn when indexing below the start of a symbolic region's whose
|
||||
// base extent we don't know.
|
||||
int *get_symbolic(void);
|
||||
@ -180,12 +172,6 @@ void test_extern_void(void) {
|
||||
p[1] = 42; // no-warning
|
||||
}
|
||||
|
||||
void test_assume_after_access2(unsigned long x) {
|
||||
char buf[100];
|
||||
buf[x] = 1;
|
||||
clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
struct incomplete;
|
||||
char test_comparison_with_extent_symbol(struct incomplete *p) {
|
||||
// Previously this was reported as a (false positive) overflow error because
|
||||
|
Loading…
x
Reference in New Issue
Block a user