275 lines · c
1// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,security.ArrayBound,debug.ExprInspection -verify %s2 3// Miscellaneous tests for `security.ArrayBound` where we only test the4// presence or absence of a bug report. If a test doesn't fit in a more5// specific file and doesn't need to verify the details of 'note' diagnostics,6// then it should be placed here.7 8void clang_analyzer_value(int);9 10// Tests doing an out-of-bounds access after the end of an array using:11// - constant integer index12// - constant integer size for buffer13void test1(int x) {14 int buf[100];15 buf[100] = 1; // expected-warning{{Out of bound access to memory}}16}17 18void test1_ok(int x) {19 int buf[100];20 buf[99] = 1; // no-warning21}22 23const char test1_strings_underrun(int x) {24 const char *mystr = "mary had a little lamb";25 return mystr[-1]; // expected-warning{{Out of bound access to memory}}26}27 28const char test1_strings_overrun(int x) {29 const char *mystr = "mary had a little lamb";30 return mystr[1000]; // expected-warning{{Out of bound access to memory}}31}32 33const char test1_strings_ok(int x) {34 const char *mystr = "mary had a little lamb";35 return mystr[5]; // no-warning36}37 38// Tests doing an out-of-bounds access after the end of an array using:39// - indirect pointer to buffer40// - constant integer index41// - constant integer size for buffer42void test1_ptr(int x) {43 int buf[100];44 int *p = buf;45 p[101] = 1; // expected-warning{{Out of bound access to memory}}46}47 48void test1_ptr_ok(int x) {49 int buf[100];50 int *p = buf;51 p[99] = 1; // no-warning52}53 54// Tests doing an out-of-bounds access before the start of an array using:55// - indirect pointer to buffer, manipulated using simple pointer arithmetic56// - constant integer index57// - constant integer size for buffer58void test1_ptr_arith(int x) {59 int buf[100];60 int *p = buf;61 p = p + 100;62 p[0] = 1; // expected-warning{{Out of bound access to memory}}63}64 65void test1_ptr_arith_ok(int x) {66 int buf[100];67 int *p = buf;68 p = p + 99;69 p[0] = 1; // no-warning70}71 72void test1_ptr_arith_bad(int x) {73 int buf[100];74 int *p = buf;75 p = p + 99;76 p[1] = 1; // expected-warning{{Out of bound access to memory}}77}78 79void test1_ptr_arith_ok2(int x) {80 int buf[100];81 int *p = buf;82 p = p + 99;83 p[-1] = 1; // no-warning84}85 86// Tests doing an out-of-bounds access before the start of an array using:87// - constant integer index88// - constant integer size for buffer89void test2(int x) {90 int buf[100];91 buf[-1] = 1; // expected-warning{{Out of bound access to memory}}92}93 94// Tests doing an out-of-bounds access before the start of an array using:95// - indirect pointer to buffer96// - constant integer index97// - constant integer size for buffer98void test2_ptr(int x) {99 int buf[100];100 int *p = buf;101 p[-1] = 1; // expected-warning{{Out of bound access to memory}}102}103 104// Tests doing an out-of-bounds access before the start of an array using:105// - indirect pointer to buffer, manipulated using simple pointer arithmetic106// - constant integer index107// - constant integer size for buffer108void test2_ptr_arith(int x) {109 int buf[100];110 int *p = buf;111 --p;112 p[0] = 1; // expected-warning {{Out of bound access to memory preceding}}113}114 115// Tests doing an out-of-bounds access before the start of a multi-dimensional116// array using:117// - constant integer indices118// - constant integer sizes for the array119void test2_multi(int x) {120 int buf[100][100];121 buf[0][-1] = 1; // expected-warning{{Out of bound access to memory}}122}123 124// Tests doing an out-of-bounds access before the start of a multi-dimensional125// array using:126// - constant integer indices127// - constant integer sizes for the array128void test2_multi_b(int x) {129 int buf[100][100];130 buf[-1][0] = 1; // expected-warning{{Out of bound access to memory}}131}132 133void test2_multi_ok(int x) {134 int buf[100][100];135 buf[0][0] = 1; // no-warning136}137 138void test3(int x) {139 int buf[100];140 if (x < 0)141 buf[x] = 1; // expected-warning{{Out of bound access to memory}}142}143 144void test4(int x) {145 int buf[100];146 if (x > 99)147 buf[x] = 1; // expected-warning{{Out of bound access to memory}}148}149 150// Don't warn when indexing below the start of a symbolic region's whose151// base extent we don't know.152int *get_symbolic(void);153void test_underflow_symbolic(void) {154 int *buf = get_symbolic();155 buf[-1] = 0; // no-warning156}157 158// But warn if we understand the internal memory layout of a symbolic region.159typedef struct {160 int id;161 char name[256];162} user_t;163 164user_t *get_symbolic_user(void);165char test_underflow_symbolic_2() {166 user_t *user = get_symbolic_user();167 return user->name[-1]; // expected-warning{{Out of bound access to memory}}168}169 170void test_incomplete_struct(void) {171 extern struct incomplete incomplete;172 int *p = (int *)&incomplete;173 p[1] = 42; // no-warning174}175 176void test_extern_void(void) {177 extern void v;178 int *p = (int *)&v;179 p[1] = 42; // no-warning180}181 182struct incomplete;183char test_comparison_with_extent_symbol(struct incomplete *p) {184 // Previously this was reported as a (false positive) overflow error because185 // the extent symbol of the area pointed by `p` was an unsigned and the '-1'186 // was converted to its type by `evalBinOpNN`.187 return ((char *)p)[-1]; // no-warning188}189 190int table[256], small_table[128];191int test_cast_to_unsigned(signed char x) {192 unsigned char y = x;193 if (x >= 0)194 return x;195 // FIXME: Here the analyzer ignores the signed -> unsigned cast, and manages to196 // load a negative value from an unsigned variable.197 // The underlying issue is tracked by Github ticket #39492.198 clang_analyzer_value(y); // expected-warning {{8s:{ [-128, -1] } }}199 // However, a hack in the ArrayBound checker suppresses the false positive200 // underflow report that would be generated here.201 return table[y]; // no-warning202}203 204int test_cast_to_unsigned_overflow(signed char x) {205 unsigned char y = x;206 if (x >= 0)207 return x;208 // FIXME: As in 'test_cast_to_unsigned', the analyzer thinks that this209 // unsigned variable contains a negative value.210 clang_analyzer_value(y); // expected-warning {{8s:{ [-128, -1] } }}211 // FIXME: The following subscript expression should produce an overflow212 // report (because negative signed char corresponds to unsigned char >= 128);213 // but the hack in ArrayBound just silences reports and cannot "restore" the214 // real execution paths.215 return small_table[y]; // no-warning216}217 218int test_negative_offset_with_unsigned_idx(void) {219 // An example where the subscript operator uses an unsigned index, but the220 // underflow report is still justified.221 int *p = table - 10;222 unsigned idx = 2u;223 return p[idx]; // expected-warning {{Out of bound access to memory preceding}}224}225 226struct three_words { int c[3]; };227struct seven_words { int c[7]; };228void partially_in_bounds(void) {229 struct seven_words c;230 struct three_words a, *p = (struct three_words *)&c;231 p[0] = a; // no-warning232 p[1] = a; // no-warning233 p[2] = a; // should warn234 // FIXME: This is an overflow, but currently security.ArrayBound only checks235 // that the _beginning_ of the accessed element is within bounds.236}237 238void vla(int a) {239 if (a == 5) {240 int x[a];241 x[4] = 4; // no-warning242 x[5] = 5; // expected-warning{{Out of bound access}}243 }244}245 246void sizeof_vla(int a) {247 // FIXME: VLA modeling is not good enough to cover this case.248 if (a == 5) {249 char x[a];250 int y[sizeof(x)];251 y[4] = 4; // no-warning252 y[5] = 5; // should be {{Out of bounds access}}253 }254}255 256void sizeof_vla_2(int a) {257 // FIXME: VLA modeling is not good enough to cover this case.258 if (a == 5) {259 char x[a];260 int y[sizeof(x) / sizeof(char)];261 y[4] = 4; // no-warning262 y[5] = 5; // should be {{Out of bounds access}}263 }264}265 266void sizeof_vla_3(int a) {267 // FIXME: VLA modeling is not good enough to cover this case.268 if (a == 5) {269 char x[a];270 int y[sizeof(*&*&*&x)];271 y[4] = 4; // no-warning272 y[5] = 5; // should be {{Out of bounds access}}273 }274}275