278 lines · cpp
1// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -verify %s -triple x86_64-pc-linux-gnu \2// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm3 4// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -verify %s -triple x86_64-pc-linux-gnu \5// RUN: -analyzer-config support-symbolic-integer-casts=true \6// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm7 8template <typename T> void clang_analyzer_dump(T);9 10struct X {11 int *p;12 int zero;13 void foo () {14 reset(p - 1);15 }16 void reset(int *in) {17 while (in != p) // Loop must be entered.18 zero = 1;19 }20};21 22int test (int *in) {23 X littleX;24 littleX.zero = 0;25 littleX.p = in;26 littleX.foo();27 return 5/littleX.zero; // no-warning28}29 30 31class Base {};32class Derived : public Base {};33 34void checkPolymorphicUse() {35 Derived d[10];36 37 Base *p = d;38 ++p; // expected-warning{{Pointer arithmetic on a pointer to base class is dangerous}}39}40 41void checkBitCasts() {42 long l;43 char *p = (char*)&l;44 p = p+2;45}46 47void checkBasicarithmetic(int i) {48 int t[10];49 int *p = t;50 ++p;51 int a = 5;52 p = &a;53 ++p; // expected-warning{{Pointer arithmetic on non-array variables relies on memory layout, which is dangerous}}54 p = p + 2; // expected-warning{{}}55 p = 2 + p; // expected-warning{{}}56 p += 2; // expected-warning{{}}57 a += p[2]; // expected-warning{{}}58 p = i*0 + p;59 p = p + i*0;60 p += i*0;61}62 63void checkArithOnSymbolic(int*p) {64 ++p;65 p = p + 2;66 p = 2 + p;67 p += 2;68 (void)p[2];69}70 71struct S {72 int t[10];73};74 75void arrayInStruct() {76 S s;77 int * p = s.t;78 ++p;79 S *sp = new S;80 p = sp->t;81 ++p;82 delete sp;83}84 85void checkNew() {86 int *p = new int;87 p[1] = 1; // expected-warning{{}}88}89 90void InitState(int* state) {91 state[1] = 1; // expected-warning{{}}92}93 94int* getArray(int size) {95 if (size == 0)96 return new int;97 return new int[5];98}99 100void checkConditionalArray() {101 int* maybeArray = getArray(0);102 InitState(maybeArray);103}104 105void checkMultiDimansionalArray() {106 int a[5][5];107 *(*(a+1)+2) = 2;108}109 110unsigned ptrSubtractionNoCrash(char *Begin, char *End) {111 auto N = End - Begin;112 if (Begin)113 return 0;114 return N;115}116 117// Bug 34309118bool ptrAsIntegerSubtractionNoCrash(__UINTPTR_TYPE__ x, char *p) {119 __UINTPTR_TYPE__ y = (__UINTPTR_TYPE__)p - 1;120 return y == x;121}122 123// Bug 34374124bool integerAsPtrSubtractionNoCrash(char *p, __UINTPTR_TYPE__ m) {125 auto n = p - reinterpret_cast<char*>((__UINTPTR_TYPE__)1);126 return n == m;127}128 129namespace Bug_55934 {130struct header {131 unsigned a : 1;132 unsigned b : 1;133};134struct parse_t {135 unsigned bits0 : 1;136 unsigned bits2 : 2; // <-- header137 unsigned bits4 : 4;138};139int parse(parse_t *p) {140 unsigned copy = p->bits2;141 clang_analyzer_dump(copy);142 // expected-warning@-1 {{reg_$2<unsigned int Element{SymRegion{reg_$0<parse_t * p>},0 S64b,struct Bug_55934::parse_t}.bits2>}}143 header *bits = (header *)©144 clang_analyzer_dump(bits->b);145 // expected-warning@-1 {{derived_$4{reg_$2<unsigned int Element{SymRegion{reg_$0<parse_t * p>},0 S64b,struct Bug_55934::parse_t}.bits2>,Element{copy,0 S64b,struct Bug_55934::header}.b}}}146 return bits->b; // no-warning147}148} // namespace Bug_55934149 150void LValueToRValueBitCast_dumps(void *p, char (*array)[8]) {151 clang_analyzer_dump(p);152 clang_analyzer_dump(array);153 // expected-warning@-2 {{&SymRegion{reg_$0<void * p>}}}154 // expected-warning@-2 {{&SymRegion{reg_$1<char (*)[8] array>}}}155 clang_analyzer_dump((unsigned long)p);156 clang_analyzer_dump(__builtin_bit_cast(unsigned long, p));157 // expected-warning@-2 {{&SymRegion{reg_$0<void * p>} [as 64 bit integer]}}158 // expected-warning@-2 {{&SymRegion{reg_$0<void * p>} [as 64 bit integer]}}159 clang_analyzer_dump((unsigned long)array);160 clang_analyzer_dump(__builtin_bit_cast(unsigned long, array));161 // expected-warning@-2 {{&SymRegion{reg_$1<char (*)[8] array>} [as 64 bit integer]}}162 // expected-warning@-2 {{&SymRegion{reg_$1<char (*)[8] array>} [as 64 bit integer]}}163}164 165unsigned long ptr_arithmetic(void *p) {166 return __builtin_bit_cast(unsigned long, p) + 1; // no-crash167}168 169struct AllocOpaqueFlag {};170 171void *operator new(unsigned long, void *ptr) noexcept { return ptr; }172void *operator new(unsigned long, void *ptr, AllocOpaqueFlag const &) noexcept;173 174void *operator new[](unsigned long, void *ptr) noexcept { return ptr; }175void *operator new[](unsigned long, void *ptr,176 AllocOpaqueFlag const &) noexcept;177 178struct Buffer {179 char buf[100];180 int padding;181};182 183void checkPlacementNewArryInObject() {184 Buffer buffer;185 int *array = new (&buffer) int[10];186 ++array; // no warning187 (void)*array;188}189 190void checkPlacementNewArrayInObjectOpaque() {191 Buffer buffer;192 int *array = new (&buffer, AllocOpaqueFlag{}) int[10];193 ++array; // no warning194 (void)*array;195}196 197void checkPlacementNewArrayInArray() {198 char buffer[100];199 int *array = new (buffer) int[10];200 ++array; // no warning201 (void)*array;202}203 204void checkPlacementNewArrayInArrayOpaque() {205 char buffer[100];206 int *array = new (buffer, AllocOpaqueFlag{}) int;207 ++array; // no warning208 (void)*array;209}210 211void checkPlacementNewObjectInObject() {212 Buffer buffer;213 int *array = new (&buffer) int;214 ++array; // expected-warning{{Pointer arithmetic on non-array variables relies on memory layout, which is dangerous}}215 (void)*array;216}217 218void checkPlacementNewObjectInObjectOpaque() {219 Buffer buffer;220 int *array = new (&buffer, AllocOpaqueFlag{}) int;221 ++array; // no warning (allocator is opaque)222 (void)*array;223}224 225void checkPlacementNewObjectInArray() {226 char buffer[sizeof(int)];227 int *array = new (buffer) int;228 ++array; // no warning (FN)229 (void)*array;230}231 232void checkPlacementNewObjectInArrayOpaque() {233 char buffer[sizeof(int)];234 int *array = new (buffer, AllocOpaqueFlag{}) int;235 ++array; // no warning (FN)236 (void)*array;237}238 239void checkPlacementNewSlices() {240 const int N = 10;241 char buffer[sizeof(int) * N] = {0};242 int *start = new (buffer) int{0};243 for (int i = 1; i < N; i++) {244 auto *ptr = new int(buffer[i * sizeof(int)]);245 *ptr = i;246 }247 ++start; // no warning248 (void *)start;249}250 251class BumpAlloc {252 char *buffer;253 char *offset;254 255public:256 BumpAlloc(int n) : buffer(new char[n]), offset{buffer} {}257 ~BumpAlloc() { delete[] buffer; }258 259 void *alloc(unsigned long size) {260 auto *ptr = offset;261 offset += size;262 return ptr;263 }264};265 266void *operator new(unsigned long size, BumpAlloc &ba) { return ba.alloc(size); }267 268void checkPlacementSlab() {269 BumpAlloc bump{10};270 271 int *ptr = new (bump) int{0};272 ++ptr; // no warning273 (void)*ptr;274 275 BumpAlloc *why = ≎276 ++why; // expected-warning {{Pointer arithmetic on non-array variables relies on memory layout, which is dangerous [alpha.core.PointerArithm]}}277}278