| // RUN: %clang_analyze_cc1 -std=c++11 -Wno-array-bounds -analyzer-checker=unix,core,security.ArrayBound -verify %s | |
| // Test the interactions of `security.ArrayBound` with C++ features. | |
| // 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 = new int[100]; | |
| buf[100] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| void test1_ok(int x) { | |
| int *buf = new int[100]; | |
| buf[99] = 1; // 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 = new int[100]; | |
| int *p = buf; | |
| p[101] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| void test1_ptr_ok(int x) { | |
| int *buf = new int[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 = new int[100]; | |
| int *p = buf; | |
| p = p + 100; | |
| p[0] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| void test1_ptr_arith_ok(int x) { | |
| int *buf = new int[100]; | |
| int *p = buf; | |
| p = p + 99; | |
| p[0] = 1; // no-warning | |
| } | |
| void test1_ptr_arith_bad(int x) { | |
| int *buf = new int[100]; | |
| int *p = buf; | |
| p = p + 99; | |
| p[1] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| void test1_ptr_arith_ok2(int x) { | |
| int *buf = new int[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 = new int[100]; | |
| buf[-1] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // 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 = new int[100]; | |
| int *p = buf; | |
| p[-1] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // 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 = new int[100]; | |
| int *p = buf; | |
| --p; | |
| p[0] = 1; // expected-warning {{Out of bound access to memory preceding}} | |
| } | |
| // Tests under-indexing | |
| // of a multi-dimensional array | |
| void test2_multi(int x) { | |
| auto buf = new int[100][100]; | |
| buf[0][-1] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // Tests under-indexing | |
| // of a multi-dimensional array | |
| void test2_multi_b(int x) { | |
| auto buf = new int[100][100]; | |
| buf[-1][0] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // Tests over-indexing | |
| // of a multi-dimensional array | |
| void test2_multi_c(int x) { | |
| auto buf = new int[100][100]; | |
| buf[100][0] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // Tests over-indexing | |
| // of a multi-dimensional array | |
| void test2_multi_2(int x) { | |
| auto buf = new int[100][100]; | |
| buf[99][100] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // Tests normal access of | |
| // a multi-dimensional array | |
| void test2_multi_ok(int x) { | |
| auto buf = new int[100][100]; | |
| buf[0][0] = 1; // no-warning | |
| } | |
| // Tests over-indexing using different types | |
| // array | |
| void test_diff_types(int x) { | |
| int *buf = new int[10]; //10*sizeof(int) Bytes allocated | |
| char *cptr = (char *)buf; | |
| cptr[sizeof(int) * 9] = 1; // no-warning | |
| cptr[sizeof(int) * 10] = 1; // expected-warning{{Out of bound access to memory}} | |
| } | |
| // Tests over-indexing | |
| //if the allocated area is non-array | |
| void test_non_array(int x) { | |
| int *ip = new int; | |
| ip[0] = 1; // no-warning | |
| ip[1] = 2; // expected-warning{{Out of bound access to memory}} | |
| } | |
| //Tests over-indexing | |
| //if the allocated area size is a runtime parameter | |
| void test_dynamic_size(int s) { | |
| int *buf = new int[s]; | |
| buf[0] = 1; // no-warning | |
| } | |
| //Tests complex arithmetic | |
| //in new expression | |
| void test_dynamic_size2(unsigned m, unsigned n){ | |
| unsigned *U = nullptr; | |
| U = new unsigned[m + n + 1]; | |
| } | |
| //Test creating invalid references, which break the invariant that a reference | |
| //is always holding a value, and could lead to nasty runtime errors. | |
| int array[10] = {0}; | |
| void test_after_the_end_reference() { | |
| int &ref = array[10]; // expected-warning{{Out of bound access to memory}} | |
| } | |
| void test_after_after_the_end_reference() { | |
| int &ref = array[11]; // expected-warning{{Out of bound access to memory}} | |
| } | |
| int test_reference_that_might_be_after_the_end(int idx) { | |
| // This TC produces no warning because separate analysis of (idx == 10) is | |
| // only introduced _after_ the creation of the reference ref. | |
| if (idx < 0 || idx > 10) | |
| return -2; | |
| int &ref = array[idx]; | |
| if (idx == 10) | |
| return -1; | |
| return ref; | |
| } |