Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 155 additions & 104 deletions clang/test/Analysis/out-of-bounds-constraint-check.c
Original file line number Diff line number Diff line change
@@ -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);

typedef typeof(sizeof(int)) size_t;
const char a[] = "abcd"; // extent: 5 bytes

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}}
}

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 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 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 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 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 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}}
// 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.

void clang_analyzer_value(int);

// 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 int_neutral(int len) {
(void)FiveInts[len]; // no-warning
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
}

void int_minus_one(int len) {
(void)FiveInts[len - 1]; // no-warning
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
}

void unsigned_plus_one(unsigned len) {
(void)FiveInts[len + 1]; // no-warning
clang_analyzer_value(len); // expected-warning {{{ [0, 3] }}}
}

void unsigned_neutral(unsigned len) {
(void)FiveInts[len]; // no-warning
clang_analyzer_value(len); // expected-warning {{{ [0, 4] }}}
}

void unsigned_minus_one(unsigned len) {
(void)FiveInts[len - 1]; // no-warning
clang_analyzer_value(len); // expected-warning {{{ [1, 5] }}}
}

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 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 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_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 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 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);
}
16 changes: 1 addition & 15 deletions clang/test/Analysis/out-of-bounds.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down