1 // RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-output=text \ 2 // RUN: -analyzer-checker=core,alpha.security.ArrayBoundV2,unix.Malloc,optin.taint -verify %s 3 4 int TenElements[10]; 5 6 void arrayUnderflow(void) { 7 TenElements[-3] = 5; 8 // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} 9 // expected-note@-2 {{Access of 'TenElements' at negative byte offset -12}} 10 } 11 12 int underflowWithDeref(void) { 13 int *p = TenElements; 14 --p; 15 return *p; 16 // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} 17 // expected-note@-2 {{Access of 'TenElements' at negative byte offset -4}} 18 } 19 20 int rng(void); 21 int getIndex(void) { 22 switch (rng()) { 23 case 1: return -152; 24 case 2: return -160; 25 case 3: return -168; 26 default: return -172; 27 } 28 } 29 30 void gh86959(void) { 31 // Previously code like this produced many almost-identical bug reports that 32 // only differed in the offset value. Verify that now we only see one report. 33 34 // expected-note@+1 {{Entering loop body}} 35 while (rng()) 36 TenElements[getIndex()] = 10; 37 // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} 38 // expected-note@-2 {{Access of 'TenElements' at negative byte offset -688}} 39 } 40 41 int scanf(const char *restrict fmt, ...); 42 43 void taintedIndex(void) { 44 int index; 45 scanf("%d", &index); 46 // expected-note@-1 {{Taint originated here}} 47 // expected-note@-2 {{Taint propagated to the 2nd argument}} 48 TenElements[index] = 5; 49 // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}} 50 // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be negative or too large}} 51 } 52 53 void taintedIndexNonneg(void) { 54 int index; 55 scanf("%d", &index); 56 // expected-note@-1 {{Taint originated here}} 57 // expected-note@-2 {{Taint propagated to the 2nd argument}} 58 59 // expected-note@+2 {{Assuming 'index' is >= 0}} 60 // expected-note@+1 {{Taking false branch}} 61 if (index < 0) 62 return; 63 64 TenElements[index] = 5; 65 // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}} 66 // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}} 67 } 68 69 void taintedIndexUnsigned(void) { 70 unsigned index; 71 scanf("%u", &index); 72 // expected-note@-1 {{Taint originated here}} 73 // expected-note@-2 {{Taint propagated to the 2nd argument}} 74 75 TenElements[index] = 5; 76 // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}} 77 // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}} 78 } 79 80 int *taintedIndexAfterTheEndPtr(void) { 81 // NOTE: Technically speaking, this testcase does not trigger any UB because 82 // &TenElements[10] is the after-the-end pointer which is well-defined; but 83 // this is a bug-prone situation and far from the idiomatic use of 84 // `&TenElements[size]`, so it's better to report an error. This report can 85 // be easily silenced by writing TenElements+index instead of 86 // &TenElements[index]. 87 int index; 88 scanf("%d", &index); 89 // expected-note@-1 {{Taint originated here}} 90 // expected-note@-2 {{Taint propagated to the 2nd argument}} 91 if (index < 0 || index > 10) 92 return TenElements; 93 // expected-note@-2 {{Assuming 'index' is >= 0}} 94 // expected-note@-3 {{Left side of '||' is false}} 95 // expected-note@-4 {{Assuming 'index' is <= 10}} 96 // expected-note@-5 {{Taking false branch}} 97 return &TenElements[index]; 98 // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}} 99 // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}} 100 } 101 102 void taintedOffset(void) { 103 int index; 104 scanf("%d", &index); 105 // expected-note@-1 {{Taint originated here}} 106 // expected-note@-2 {{Taint propagated to the 2nd argument}} 107 int *p = TenElements + index; 108 p[0] = 5; 109 // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted offset}} 110 // expected-note@-2 {{Access of 'TenElements' with a tainted offset that may be negative or too large}} 111 } 112 113 void arrayOverflow(void) { 114 TenElements[12] = 5; 115 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 116 // expected-note@-2 {{Access of 'TenElements' at index 12, while it holds only 10 'int' elements}} 117 } 118 119 void flippedOverflow(void) { 120 12[TenElements] = 5; 121 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 122 // expected-note@-2 {{Access of 'TenElements' at index 12, while it holds only 10 'int' elements}} 123 } 124 125 int *afterTheEndPtr(void) { 126 // This is an unusual but standard-compliant way of writing (TenElements + 10). 127 return &TenElements[10]; // no-warning 128 } 129 130 int useAfterTheEndPtr(void) { 131 // ... but dereferencing the after-the-end pointer is still invalid. 132 return *afterTheEndPtr(); 133 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 134 // expected-note@-2 {{Access of 'TenElements' at index 10, while it holds only 10 'int' elements}} 135 } 136 137 int *afterAfterTheEndPtr(void) { 138 // This is UB, it's invalid to form an after-after-the-end pointer. 139 return &TenElements[11]; 140 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 141 // expected-note@-2 {{Access of 'TenElements' at index 11, while it holds only 10 'int' elements}} 142 } 143 144 int *potentialAfterTheEndPtr(int idx) { 145 if (idx < 10) { /* ...do something... */ } 146 // expected-note@-1 {{Assuming 'idx' is >= 10}} 147 // expected-note@-2 {{Taking false branch}} 148 return &TenElements[idx]; 149 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 150 // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} 151 // NOTE: On the idx >= 10 branch the normal "optimistic" behavior would've 152 // been continuing with the assumption that idx == 10 and the return value is 153 // a legitimate after-the-end pointer. The checker deviates from this by 154 // reporting an error because this situation is very suspicious and far from 155 // the idiomatic `&TenElements[size]` expressions. If the report is FP, the 156 // developer can easily silence it by writing TenElements+idx instead of 157 // &TenElements[idx]. 158 } 159 160 int overflowOrUnderflow(int arg) { 161 // expected-note@+2 {{Assuming 'arg' is < 0}} 162 // expected-note@+1 {{Taking false branch}} 163 if (arg >= 0) 164 return 0; 165 166 return TenElements[arg - 1]; 167 // expected-warning@-1 {{Out of bound access to memory around 'TenElements'}} 168 // expected-note@-2 {{Access of 'TenElements' at a negative or overflowing index, while it holds only 10 'int' elements}} 169 } 170 171 char TwoElements[2] = {11, 22}; 172 char overflowOrUnderflowConcrete(int arg) { 173 // expected-note@#cond {{Assuming 'arg' is < 3}} 174 // expected-note@#cond {{Left side of '||' is false}} 175 // expected-note@#cond {{Assuming 'arg' is not equal to 0}} 176 // expected-note@#cond {{Left side of '||' is false}} 177 // expected-note@#cond {{Assuming 'arg' is not equal to 1}} 178 // expected-note@#cond {{Taking false branch}} 179 if (arg >= 3 || arg == 0 || arg == 1) // #cond 180 return 0; 181 182 return TwoElements[arg]; 183 // expected-warning@-1 {{Out of bound access to memory around 'TwoElements'}} 184 // expected-note@-2 {{Access of 'TwoElements' at a negative or overflowing index, while it holds only 2 'char' elements}} 185 } 186 187 int scalar; 188 int scalarOverflow(void) { 189 return (&scalar)[1]; 190 // expected-warning@-1 {{Out of bound access to memory after the end of 'scalar'}} 191 // expected-note@-2 {{Access of 'scalar' at index 1, while it holds only a single 'int' element}} 192 } 193 194 int oneElementArray[1]; 195 int oneElementArrayOverflow(void) { 196 return oneElementArray[1]; 197 // expected-warning@-1 {{Out of bound access to memory after the end of 'oneElementArray'}} 198 // expected-note@-2 {{Access of 'oneElementArray' at index 1, while it holds only a single 'int' element}} 199 } 200 201 struct vec { 202 int len; 203 double elems[64]; 204 } v; 205 206 double arrayInStruct(void) { 207 return v.elems[64]; 208 // expected-warning@-1 {{Out of bound access to memory after the end of 'v.elems'}} 209 // expected-note@-2 {{Access of 'v.elems' at index 64, while it holds only 64 'double' elements}} 210 } 211 212 double arrayInStructPtr(struct vec *pv) { 213 return pv->elems[64]; 214 // expected-warning@-1 {{Out of bound access to memory after the end of the field 'elems'}} 215 // expected-note@-2 {{Access of the field 'elems' at index 64, while it holds only 64 'double' elements}} 216 } 217 218 struct item { 219 int a, b; 220 } itemArray[20] = {0}; 221 222 int arrayOfStructs(void) { 223 return itemArray[35].a; 224 // expected-warning@-1 {{Out of bound access to memory after the end of 'itemArray'}} 225 // expected-note@-2 {{Access of 'itemArray' at index 35, while it holds only 20 'struct item' elements}} 226 } 227 228 int arrayOfStructsArrow(void) { 229 return (itemArray + 35)->b; 230 // expected-warning@-1 {{Out of bound access to memory after the end of 'itemArray'}} 231 // expected-note@-2 {{Access of 'itemArray' at index 35, while it holds only 20 'struct item' elements}} 232 } 233 234 short convertedArray(void) { 235 return ((short*)TenElements)[47]; 236 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 237 // expected-note@-2 {{Access of 'TenElements' at index 47, while it holds only 20 'short' elements}} 238 } 239 240 struct two_bytes { 241 char lo, hi; 242 }; 243 244 struct two_bytes convertedArray2(void) { 245 // We report this with byte offsets because the offset is not divisible by the element size. 246 struct two_bytes a = {0, 0}; 247 char *p = (char*)&a; 248 return *((struct two_bytes*)(p + 7)); 249 // expected-warning@-1 {{Out of bound access to memory after the end of 'a'}} 250 // expected-note@-2 {{Access of 'a' at byte offset 7, while it holds only 2 bytes}} 251 } 252 253 int intFromString(void) { 254 // We report this with byte offsets because the extent is not divisible by the element size. 255 return ((const int*)"this is a string of 33 characters")[20]; 256 // expected-warning@-1 {{Out of bound access to memory after the end of the string literal}} 257 // expected-note@-2 {{Access of the string literal at byte offset 80, while it holds only 34 bytes}} 258 } 259 260 int intFromStringDivisible(void) { 261 // However, this is reported with indices/elements, because the extent 262 // (of the string that consists of 'a', 'b', 'c' and '\0') happens to be a 263 // multiple of 4 bytes (= sizeof(int)). 264 return ((const int*)"abc")[20]; 265 // expected-warning@-1 {{Out of bound access to memory after the end of the string literal}} 266 // expected-note@-2 {{Access of the string literal at index 20, while it holds only a single 'int' element}} 267 } 268 269 typedef __typeof(sizeof(int)) size_t; 270 void *malloc(size_t size); 271 272 int *mallocRegion(void) { 273 int *mem = (int*)malloc(2*sizeof(int)); 274 275 mem[3] = -2; 276 // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} 277 // expected-note@-2 {{Access of the heap area at index 3, while it holds only 2 'int' elements}} 278 return mem; 279 } 280 281 int *custom_calloc(size_t a, size_t b) { 282 size_t res; 283 284 return __builtin_mul_overflow(a, b, &res) ? 0 : malloc(res); 285 } 286 287 int *mallocRegionOverflow(void) { 288 int *mem = (int*)custom_calloc(10, sizeof(int)); 289 290 mem[20] = 10; 291 // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} 292 // expected-note@-2 {{Access of the heap area at index 20, while it holds only 10 'int' elements}} 293 return mem; 294 } 295 296 int *mallocRegionDeref(void) { 297 int *mem = (int*)malloc(2*sizeof(int)); 298 299 *(mem + 3) = -2; 300 // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} 301 // expected-note@-2 {{Access of the heap area at index 3, while it holds only 2 'int' elements}} 302 return mem; 303 } 304 305 void *alloca(size_t size); 306 307 int allocaRegion(void) { 308 int *mem = (int*)alloca(2*sizeof(int)); 309 mem[3] = -2; 310 // expected-warning@-1 {{Out of bound access to memory after the end of the memory returned by 'alloca'}} 311 // expected-note@-2 {{Access of the memory returned by 'alloca' at index 3, while it holds only 2 'int' elements}} 312 return *mem; 313 } 314 315 int *symbolicExtent(int arg) { 316 // expected-note@+2 {{Assuming 'arg' is < 5}} 317 // expected-note@+1 {{Taking false branch}} 318 if (arg >= 5) 319 return 0; 320 int *mem = (int*)malloc(arg); 321 322 // TODO: without the following reference to 'arg', the analyzer would discard 323 // the range information about (the symbolic value of) 'arg'. This is 324 // incorrect because while the variable itself is inaccessible, it becomes 325 // the symbolic extent of 'mem', so we still want to reason about its 326 // potential values. 327 (void)arg; 328 329 mem[8] = -2; 330 // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} 331 // expected-note@-2 {{Access of 'int' element in the heap area at index 8}} 332 return mem; 333 } 334 335 int *symbolicExtentDiscardedRangeInfo(int arg) { 336 // This is a copy of the case 'symbolicExtent' without the '(void)arg' hack. 337 // TODO: if the analyzer can detect the out-of-bounds access within this 338 // testcase, then remove this and the `(void)arg` hack from `symbolicExtent`. 339 if (arg >= 5) 340 return 0; 341 int *mem = (int*)malloc(arg); 342 mem[8] = -2; 343 return mem; 344 } 345 346 void symbolicIndex(int arg) { 347 // expected-note@+2 {{Assuming 'arg' is >= 12}} 348 // expected-note@+1 {{Taking true branch}} 349 if (arg >= 12) 350 TenElements[arg] = -2; 351 // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} 352 // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} 353 } 354 355 int *nothingIsCertain(int x, int y) { 356 if (x >= 2) 357 return 0; 358 int *mem = (int*)malloc(x); 359 360 if (y >= 8) 361 mem[y] = -2; 362 // FIXME: this should produce 363 // {{Out of bound access to memory after the end of the heap area}} 364 // {{Access of 'int' element in the heap area at an overflowing index}} 365 // but apparently the analyzer isn't smart enough to deduce this. 366 367 // Keep constraints alive. (Without this, the overeager garbage collection of 368 // constraints would _also_ prevent the intended behavior in this testcase.) 369 (void)x; 370 371 return mem; 372 } 373