brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.4 KiB · c0da93e Raw
413 lines · c
1// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-output=text        \2// RUN:     -analyzer-checker=core,security.ArrayBound,unix.Malloc,optin.taint -verify %s3 4// Miscellaneous tests for `security.ArrayBound` where we also verify the5// content of the 'note' diagnostics. This makes the tests sensitive to textual6// changes in the diagnostics, so prefer adding new tests to `brief-tests.c`7// unless they need to verify the correctness of 'note' diagnostics.8 9int TenElements[10];10 11void arrayUnderflow(void) {12  TenElements[-3] = 5;13  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}14  // expected-note@-2 {{Access of 'int' element in 'TenElements' at negative index -3}}15}16 17int underflowWithDeref(void) {18  int *p = TenElements;19  --p;20  return *p;21  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}22  // expected-note@-2 {{Access of 'int' element in 'TenElements' at negative index -1}}23}24 25char underflowReportedAsChar(void) {26  // Underflow is reported with the type of the accessed element (here 'char'),27  // not the type that appears in the declaration of the original array (which28  // would be 'int').29  return ((char *)TenElements)[-1];30  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}31  // expected-note@-2 {{Access of 'char' element in 'TenElements' at negative index -1}}32}33 34struct TwoInts {35  int a, b;36};37 38struct TwoInts underflowReportedAsStruct(void) {39  // Another case where the accessed type is used for reporting the offset.40  return *(struct TwoInts*)(TenElements - 4);41  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}42  // expected-note@-2 {{Access of 'struct TwoInts' element in 'TenElements' at negative index -2}}43}44 45struct TwoInts underflowOnlyByteOffset(void) {46  // In this case the negative byte offset is not a multiple of the size of the47  // accessed element, so the part "= -... * sizeof(type)" is omitted at the48  // end of the message.49  return *(struct TwoInts*)(TenElements - 3);50  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}51  // expected-note@-2 {{Access of 'TenElements' at negative byte offset -12}}52}53 54 55int rng(void);56int getIndex(void) {57  switch (rng()) {58    case 1: return -152;59    case 2: return -160;60    case 3: return -168;61    default: return -172;62  }63}64 65void gh86959(void) {66  // Previously code like this produced many almost-identical bug reports that67  // only differed in the offset value. Verify that now we only see one report.68 69  // expected-note@+1 {{Entering loop body}}70  while (rng())71    TenElements[getIndex()] = 10;72  // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}}73  // expected-note@-2 {{Access of 'int' element in 'TenElements' at negative index -172}}74}75 76int scanf(const char *fmt, ...);77 78void taintedIndex(void) {79  int index;80  scanf("%d", &index);81  // expected-note@-1 {{Taint originated here}}82  // expected-note@-2 {{Taint propagated to the 2nd argument}}83  TenElements[index] = 5;84  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}}85  // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be negative or too large}}86}87 88void taintedIndexNonneg(void) {89  int index;90  scanf("%d", &index);91  // expected-note@-1 {{Taint originated here}}92  // expected-note@-2 {{Taint propagated to the 2nd argument}}93 94  // expected-note@+2 {{Assuming 'index' is >= 0}}95  // expected-note@+1 {{Taking false branch}}96  if (index < 0)97    return;98 99  TenElements[index] = 5;100  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}}101  // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}}102}103 104void taintedIndexUnsigned(void) {105  unsigned index;106  scanf("%u", &index);107  // expected-note@-1 {{Taint originated here}}108  // expected-note@-2 {{Taint propagated to the 2nd argument}}109 110  TenElements[index] = 5;111  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}}112  // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}}113}114 115int *taintedIndexAfterTheEndPtr(void) {116  // NOTE: Technically speaking, this testcase does not trigger any UB because117  // &TenElements[10] is the after-the-end pointer which is well-defined; but118  // this is a bug-prone situation and far from the idiomatic use of119  // `&TenElements[size]`, so it's better to report an error. This report can120  // be easily silenced by writing TenElements+index instead of121  // &TenElements[index].122  int index;123  scanf("%d", &index);124  // expected-note@-1 {{Taint originated here}}125  // expected-note@-2 {{Taint propagated to the 2nd argument}}126  if (index < 0 || index > 10)127    return TenElements;128  // expected-note@-2 {{Assuming 'index' is >= 0}}129  // expected-note@-3 {{Left side of '||' is false}}130  // expected-note@-4 {{Assuming 'index' is <= 10}}131  // expected-note@-5 {{Taking false branch}}132  return &TenElements[index];133  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted index}}134  // expected-note@-2 {{Access of 'TenElements' with a tainted index that may be too large}}135}136 137void taintedOffset(void) {138  int index;139  scanf("%d", &index);140  // expected-note@-1 {{Taint originated here}}141  // expected-note@-2 {{Taint propagated to the 2nd argument}}142  int *p = TenElements + index;143  p[0] = 5;144  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with tainted offset}}145  // expected-note@-2 {{Access of 'TenElements' with a tainted offset that may be negative or too large}}146}147 148void arrayOverflow(void) {149  TenElements[12] = 5;150  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}151  // expected-note@-2 {{Access of 'TenElements' at index 12, while it holds only 10 'int' elements}}152}153 154void flippedOverflow(void) {155  12[TenElements] = 5;156  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}157  // expected-note@-2 {{Access of 'TenElements' at index 12, while it holds only 10 'int' elements}}158}159 160int *afterTheEndPtr(void) {161  // This is an unusual but standard-compliant way of writing (TenElements + 10).162  return &TenElements[10]; // no-warning163}164 165int useAfterTheEndPtr(void) {166  // ... but dereferencing the after-the-end pointer is still invalid.167  return *afterTheEndPtr();168  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}169  // expected-note@-2 {{Access of 'TenElements' at index 10, while it holds only 10 'int' elements}}170}171 172int *afterAfterTheEndPtr(void) {173  // This is UB, it's invalid to form an after-after-the-end pointer.174  return &TenElements[11];175  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}176  // expected-note@-2 {{Access of 'TenElements' at index 11, while it holds only 10 'int' elements}}177}178 179int *potentialAfterTheEndPtr(int idx) {180  if (idx < 10) { /* ...do something... */ }181  // expected-note@-1 {{Assuming 'idx' is >= 10}}182  // expected-note@-2 {{Taking false branch}}183  return &TenElements[idx];184  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}185  // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}}186  // NOTE: On the idx >= 10 branch the normal "optimistic" behavior would've187  // been continuing with the assumption that idx == 10 and the return value is188  // a legitimate after-the-end pointer. The checker deviates from this by189  // reporting an error because this situation is very suspicious and far from190  // the idiomatic `&TenElements[size]` expressions. If the report is FP, the191  // developer can easily silence it by writing TenElements+idx instead of192  // &TenElements[idx].193}194 195int overflowOrUnderflow(int arg) {196  // expected-note@+2 {{Assuming 'arg' is < 0}}197  // expected-note@+1 {{Taking false branch}}198  if (arg >= 0)199    return 0;200 201  return TenElements[arg - 1];202  // expected-warning@-1 {{Out of bound access to memory around 'TenElements'}}203  // expected-note@-2 {{Access of 'TenElements' at a negative or overflowing index, while it holds only 10 'int' elements}}204}205 206char TwoElements[2] = {11, 22};207char overflowOrUnderflowConcrete(int arg) {208  // expected-note@#cond {{Assuming 'arg' is < 3}}209  // expected-note@#cond {{Left side of '||' is false}}210  // expected-note@#cond {{Assuming 'arg' is not equal to 0}}211  // expected-note@#cond {{Left side of '||' is false}}212  // expected-note@#cond {{Assuming 'arg' is not equal to 1}}213  // expected-note@#cond {{Taking false branch}}214  if (arg >= 3 || arg == 0 || arg == 1) // #cond215    return 0;216 217  return TwoElements[arg];218  // expected-warning@-1 {{Out of bound access to memory around 'TwoElements'}}219  // expected-note@-2 {{Access of 'TwoElements' at a negative or overflowing index, while it holds only 2 'char' elements}}220}221 222int scalar;223int scalarOverflow(void) {224  return (&scalar)[1];225  // expected-warning@-1 {{Out of bound access to memory after the end of 'scalar'}}226  // expected-note@-2 {{Access of 'scalar' at index 1, while it holds only a single 'int' element}}227}228 229int oneElementArray[1];230int oneElementArrayOverflow(void) {231  return oneElementArray[1];232  // expected-warning@-1 {{Out of bound access to memory after the end of 'oneElementArray'}}233  // expected-note@-2 {{Access of 'oneElementArray' at index 1, while it holds only a single 'int' element}}234}235 236struct vec {237  int len;238  double elems[64];239} v;240 241double arrayInStruct(void) {242  return v.elems[64];243  // expected-warning@-1 {{Out of bound access to memory after the end of 'v.elems'}}244  // expected-note@-2 {{Access of 'v.elems' at index 64, while it holds only 64 'double' elements}}245}246 247double arrayInStructPtr(struct vec *pv) {248  return pv->elems[64];249  // expected-warning@-1 {{Out of bound access to memory after the end of the field 'elems'}}250  // expected-note@-2 {{Access of the field 'elems' at index 64, while it holds only 64 'double' elements}}251}252 253struct item {254  int a, b;255} itemArray[20] = {0};256 257int arrayOfStructs(void) {258  return itemArray[35].a;259  // expected-warning@-1 {{Out of bound access to memory after the end of 'itemArray'}}260  // expected-note@-2 {{Access of 'itemArray' at index 35, while it holds only 20 'struct item' elements}}261}262 263int arrayOfStructsArrow(void) {264  return (itemArray + 35)->b;265  // expected-warning@-1 {{Out of bound access to memory after the end of 'itemArray'}}266  // expected-note@-2 {{Access of 'itemArray' at index 35, while it holds only 20 'struct item' elements}}267}268 269char convertedScalar(long long var) {270  char *p = ((char*)&var);271  (void) p[3]; // no-warning272  return p[13];273  // expected-warning@-1 {{Out of bound access to memory after the end of 'var'}}274  // expected-note@-2 {{Access of 'var' at index 13, while it holds only 8 'char' elements}}275}276 277short convertedArray(void) {278  (void) ((short*)TenElements)[17]; // no-warning279  return ((short*)TenElements)[47];280  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}281  // expected-note@-2 {{Access of 'TenElements' at index 47, while it holds only 20 'short' elements}}282}283 284struct two_bytes {285  char lo, hi;286};287 288struct two_bytes convertedArray2(void) {289  // We report this with byte offsets because the offset is not divisible by the element size.290  struct two_bytes a = {0, 0};291  char *p = (char*)&a;292  return *((struct two_bytes*)(p + 7));293  // expected-warning@-1 {{Out of bound access to memory after the end of 'a'}}294  // expected-note@-2 {{Access of 'a' at byte offset 7, while it holds only 2 bytes}}295}296 297int intFromString(void) {298  // We report this with byte offsets because the extent is not divisible by the element size.299  return ((const int*)"this is a string of 33 characters")[20];300  // expected-warning@-1 {{Out of bound access to memory after the end of the string literal}}301  // expected-note@-2 {{Access of the string literal at byte offset 80, while it holds only 34 bytes}}302}303 304int intFromStringDivisible(void) {305  // However, this is reported with indices/elements, because the extent306  // (of the string that consists of 'a', 'b', 'c' and '\0') happens to be a307  // multiple of 4 bytes (= sizeof(int)).308  return ((const int*)"abc")[20];309  // expected-warning@-1 {{Out of bound access to memory after the end of the string literal}}310  // expected-note@-2 {{Access of the string literal at index 20, while it holds only a single 'int' element}}311}312 313typedef __typeof(sizeof(int)) size_t;314void *malloc(size_t size);315void free(void *mem);316 317int *mallocRegion(void) {318  int *mem = (int*)malloc(2*sizeof(int));319 320  mem[1] = 48; // no-warning321 322  mem[3] = -2;323  // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}}324  // expected-note@-2 {{Access of the heap area at index 3, while it holds only 2 'int' elements}}325  return mem;326}327 328typedef struct { size_t len; int data[0]; } vec_t;329 330void mallocFlexibleArray(void) {331  vec_t *v = malloc(sizeof(vec_t) + 10 * sizeof(int));332  v->len = 10;333  v->data[1] = 5; // no-warning334  v->data[11] = 99;335  // TODO: Here ideally we would expect336  //     {{Out of bound access to memory after the end of the heap area}}337  //     {{Access of the heap area at index 11, while it holds only 10 'int' elements}}338  // but the analyzer cannot (yet) deduce the size of the flexible array member339  // from the size of the whole allocated area.340  free(v);341}342 343int *custom_calloc(size_t a, size_t b) {344  size_t res;345 346  return __builtin_mul_overflow(a, b, &res) ? 0 : malloc(res);347}348 349int *mallocMulOverflow(void) {350  int *mem = (int*)custom_calloc(10, sizeof(int));351 352  mem[20] = 10;353  // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}}354  // expected-note@-2 {{Access of the heap area at index 20, while it holds only 10 'int' elements}}355  return mem;356}357 358int *mallocRegionDeref(void) {359  int *mem = (int*)malloc(2*sizeof(int));360 361  *(mem + 3) = -2;362  // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}}363  // expected-note@-2 {{Access of the heap area at index 3, while it holds only 2 'int' elements}}364  return mem;365}366 367void *alloca(size_t size);368 369int allocaRegion(void) {370  int *mem = (int*)alloca(2*sizeof(int));371  mem[3] = -2;372  // expected-warning@-1 {{Out of bound access to memory after the end of the memory returned by 'alloca'}}373  // expected-note@-2 {{Access of the memory returned by 'alloca' at index 3, while it holds only 2 'int' elements}}374  return *mem;375}376 377int *symbolicExtent(int arg) {378  // expected-note@+2 {{Assuming 'arg' is < 5}}379  // expected-note@+1 {{Taking false branch}}380  if (arg >= 5)381    return 0;382  int *mem = (int*)malloc(arg);383 384  mem[8] = -2;385  // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}}386  // expected-note@-2 {{Access of 'int' element in the heap area at index 8}}387  return mem;388}389 390void symbolicIndex(int arg) {391  // expected-note@+2 {{Assuming 'arg' is >= 12}}392  // expected-note@+1 {{Taking true branch}}393  if (arg >= 12)394    TenElements[arg] = -2;395  // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}}396  // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}}397}398 399int *nothingIsCertain(int x, int y) {400  if (x >= 2)401    return 0;402  int *mem = (int*)malloc(x);403 404  if (y >= 8)405    mem[y] = -2;406  // FIXME: this should produce407  //   {{Out of bound access to memory after the end of the heap area}}408  //   {{Access of 'int' element in the heap area at an overflowing index}}409  // but apparently the analyzer isn't smart enough to deduce this.410 411  return mem;412}413