| // RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,alpha.security.ArrayBoundV2,debug.ExprInspection -verify %s |
| |
| void clang_analyzer_eval(int); |
| |
| // Tests doing an out-of-bounds access after the end of an array using: |
| // - constant integer index |
| // - constant integer size for buffer |
| void test1(int x) { |
| int buf[100]; |
| buf[100] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test1_ok(int x) { |
| int buf[100]; |
| buf[99] = 1; // no-warning |
| } |
| |
| const char test1_strings_underrun(int x) { |
| const char *mystr = "mary had a little lamb"; |
| return mystr[-1]; // expected-warning{{Out of bound memory access}} |
| } |
| |
| const char test1_strings_overrun(int x) { |
| const char *mystr = "mary had a little lamb"; |
| return mystr[1000]; // expected-warning{{Out of bound memory access}} |
| } |
| |
| const char test1_strings_ok(int x) { |
| const char *mystr = "mary had a little lamb"; |
| return mystr[5]; // no-warning |
| } |
| |
| // Tests doing an out-of-bounds access after the end of an array using: |
| // - indirect pointer to buffer |
| // - constant integer index |
| // - constant integer size for buffer |
| void test1_ptr(int x) { |
| int buf[100]; |
| int *p = buf; |
| p[101] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test1_ptr_ok(int x) { |
| int buf[100]; |
| int *p = buf; |
| p[99] = 1; // no-warning |
| } |
| |
| // Tests doing an out-of-bounds access before the start of an array using: |
| // - indirect pointer to buffer, manipulated using simple pointer arithmetic |
| // - constant integer index |
| // - constant integer size for buffer |
| void test1_ptr_arith(int x) { |
| int buf[100]; |
| int *p = buf; |
| p = p + 100; |
| p[0] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test1_ptr_arith_ok(int x) { |
| int buf[100]; |
| int *p = buf; |
| p = p + 99; |
| p[0] = 1; // no-warning |
| } |
| |
| void test1_ptr_arith_bad(int x) { |
| int buf[100]; |
| int *p = buf; |
| p = p + 99; |
| p[1] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test1_ptr_arith_ok2(int x) { |
| int buf[100]; |
| int *p = buf; |
| p = p + 99; |
| p[-1] = 1; // no-warning |
| } |
| |
| // Tests doing an out-of-bounds access before the start of an array using: |
| // - constant integer index |
| // - constant integer size for buffer |
| void test2(int x) { |
| int buf[100]; |
| buf[-1] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| // Tests doing an out-of-bounds access before the start of an array using: |
| // - indirect pointer to buffer |
| // - constant integer index |
| // - constant integer size for buffer |
| void test2_ptr(int x) { |
| int buf[100]; |
| int *p = buf; |
| p[-1] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| // Tests doing an out-of-bounds access before the start of an array using: |
| // - indirect pointer to buffer, manipulated using simple pointer arithmetic |
| // - constant integer index |
| // - constant integer size for buffer |
| void test2_ptr_arith(int x) { |
| int buf[100]; |
| int *p = buf; |
| --p; |
| p[0] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}} |
| } |
| |
| // Tests doing an out-of-bounds access before the start of a multi-dimensional |
| // array using: |
| // - constant integer indices |
| // - constant integer sizes for the array |
| void test2_multi(int x) { |
| int buf[100][100]; |
| buf[0][-1] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| // Tests doing an out-of-bounds access before the start of a multi-dimensional |
| // array using: |
| // - constant integer indices |
| // - constant integer sizes for the array |
| void test2_multi_b(int x) { |
| int buf[100][100]; |
| buf[-1][0] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test2_multi_ok(int x) { |
| int buf[100][100]; |
| buf[0][0] = 1; // no-warning |
| } |
| |
| void test3(int x) { |
| int buf[100]; |
| if (x < 0) |
| buf[x] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| void test4(int x) { |
| int buf[100]; |
| if (x > 99) |
| buf[x] = 1; // expected-warning{{Out of bound memory access}} |
| } |
| |
| 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 test_index_below_symboloc() { |
| int *buf = get_symbolic(); |
| buf[-1] = 0; // no-warning; |
| } |
| |
| void test_incomplete_struct() { |
| extern struct incomplete incomplete; |
| int *p = (int *)&incomplete; |
| p[1] = 42; // no-warning |
| } |
| |
| void test_extern_void() { |
| extern void v; |
| int *p = (int *)&v; |
| 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}} |
| } |
| |