Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
      2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
      3 #include "Inputs/system-header-simulator-cxx.h"
      4 
      5 typedef __typeof__(sizeof(int)) size_t;
      6 extern "C" void *malloc(size_t);
      7 extern "C" void free (void* ptr);
      8 int *global;
      9 
     10 //------------------
     11 // check for leaks
     12 //------------------
     13 
     14 //----- Standard non-placement operators
     15 void testGlobalOpNew() {
     16   void *p = operator new(0);
     17 }
     18 #ifdef LEAKS
     19 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     20 #endif
     21 
     22 void testGlobalOpNewArray() {
     23   void *p = operator new[](0);
     24 }
     25 #ifdef LEAKS
     26 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     27 #endif
     28 
     29 void testGlobalNewExpr() {
     30   int *p = new int;
     31 }
     32 #ifdef LEAKS
     33 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     34 #endif
     35 
     36 void testGlobalNewExprArray() {
     37   int *p = new int[0];
     38 }
     39 #ifdef LEAKS
     40 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     41 #endif
     42 
     43 //----- Standard nothrow placement operators
     44 void testGlobalNoThrowPlacementOpNewBeforeOverload() {
     45   void *p = operator new(0, std::nothrow);
     46 }
     47 #ifdef LEAKS
     48 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     49 #endif
     50 
     51 void testGlobalNoThrowPlacementExprNewBeforeOverload() {
     52   int *p = new(std::nothrow) int;
     53 }
     54 #ifdef LEAKS
     55 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
     56 #endif
     57 
     58 //----- Standard pointer placement operators
     59 void testGlobalPointerPlacementNew() {
     60   int i;
     61 
     62   void *p1 = operator new(0, &i); // no warn
     63 
     64   void *p2 = operator new[](0, &i); // no warn
     65 
     66   int *p3 = new(&i) int; // no warn
     67 
     68   int *p4 = new(&i) int[0]; // no warn
     69 }
     70 
     71 //----- Other cases
     72 void testNewMemoryIsInHeap() {
     73   int *p = new int;
     74   if (global != p) // condition is always true as 'p' wraps a heap region that
     75                    // is different from a region wrapped by 'global'
     76     global = p; // pointer escapes
     77 }
     78 
     79 struct PtrWrapper {
     80   int *x;
     81 
     82   PtrWrapper(int *input) : x(input) {}
     83 };
     84 
     85 void testNewInvalidationPlacement(PtrWrapper *w) {
     86   // Ensure that we don't consider this a leak.
     87   new (w) PtrWrapper(new int); // no warn
     88 }
     89 
     90 //---------------
     91 // other checks
     92 //---------------
     93 
     94 class SomeClass {
     95 public:
     96   void f(int *p);
     97 };
     98 
     99 void f(int *p1, int *p2 = 0, int *p3 = 0);
    100 void g(SomeClass &c, ...);
    101 
    102 void testUseFirstArgAfterDelete() {
    103   int *p = new int;
    104   delete p;
    105   f(p); // expected-warning{{Use of memory after it is freed}}
    106 }
    107 
    108 void testUseMiddleArgAfterDelete(int *p) {
    109   delete p;
    110   f(0, p); // expected-warning{{Use of memory after it is freed}}
    111 }
    112 
    113 void testUseLastArgAfterDelete(int *p) {
    114   delete p;
    115   f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
    116 }
    117 
    118 void testUseSeveralArgsAfterDelete(int *p) {
    119   delete p;
    120   f(p, p, p); // expected-warning{{Use of memory after it is freed}}
    121 }
    122 
    123 void testUseRefArgAfterDelete(SomeClass &c) {
    124   delete &c;
    125   g(c); // expected-warning{{Use of memory after it is freed}}
    126 }
    127 
    128 void testVariadicArgAfterDelete() {
    129   SomeClass c;
    130   int *p = new int;
    131   delete p;
    132   g(c, 0, p); // expected-warning{{Use of memory after it is freed}}
    133 }
    134 
    135 void testUseMethodArgAfterDelete(int *p) {
    136   SomeClass *c = new SomeClass;
    137   delete p;
    138   c->f(p); // expected-warning{{Use of memory after it is freed}}
    139 }
    140 
    141 void testUseThisAfterDelete() {
    142   SomeClass *c = new SomeClass;
    143   delete c;
    144   c->f(0); // expected-warning{{Use of memory after it is freed}}
    145 }
    146 
    147 void testDeleteAlloca() {
    148   int *p = (int *)__builtin_alloca(sizeof(int));
    149   delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
    150 }
    151 
    152 void testDoubleDelete() {
    153   int *p = new int;
    154   delete p;
    155   delete p; // expected-warning{{Attempt to free released memory}}
    156 }
    157 
    158 void testExprDeleteArg() {
    159   int i;
    160   delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
    161 }
    162 
    163 void testExprDeleteArrArg() {
    164   int i;
    165   delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
    166 }
    167 
    168 void testAllocDeallocNames() {
    169   int *p = new(std::nothrow) int[1];
    170   delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
    171 }
    172 
    173 //--------------------------------
    174 // Test escape of newed const pointer. Note, a const pointer can be deleted.
    175 //--------------------------------
    176 struct StWithConstPtr {
    177   const int *memp;
    178 };
    179 void escape(const int &x);
    180 void escapeStruct(const StWithConstPtr &x);
    181 void escapePtr(const StWithConstPtr *x);
    182 void escapeVoidPtr(const void *x);
    183 
    184 void testConstEscape() {
    185   int *p = new int(1);
    186   escape(*p);
    187 } // no-warning
    188 
    189 void testConstEscapeStruct() {
    190   StWithConstPtr *St = new StWithConstPtr();
    191   escapeStruct(*St);
    192 } // no-warning
    193 
    194 void testConstEscapeStructPtr() {
    195   StWithConstPtr *St = new StWithConstPtr();
    196   escapePtr(St);
    197 } // no-warning
    198 
    199 void testConstEscapeMember() {
    200   StWithConstPtr St;
    201   St.memp = new int(2);
    202   escapeVoidPtr(St.memp);
    203 } // no-warning
    204 
    205 void testConstEscapePlacementNew() {
    206   int *x = (int *)malloc(sizeof(int));
    207   void *y = new (x) int;
    208   escapeVoidPtr(y);
    209 } // no-warning
    210 
    211 //============== Test Uninitialized delete delete[]========================
    212 void testUninitDelete() {
    213   int *x;
    214   int * y = new int;
    215   delete y;
    216   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
    217 }
    218 
    219 void testUninitDeleteArray() {
    220   int *x;
    221   int * y = new int[5];
    222   delete[] y;
    223   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
    224 }
    225 
    226 void testUninitFree() {
    227   int *x;
    228   free(x); // expected-warning{{Function call argument is an uninitialized value}}
    229 }
    230 
    231 void testUninitDeleteSink() {
    232   int *x;
    233   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
    234   (*(volatile int *)0 = 1); // no warn
    235 }
    236 
    237 void testUninitDeleteArraySink() {
    238   int *x;
    239   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
    240   (*(volatile int *)0 = 1); // no warn
    241 }
    242 
    243 namespace reference_count {
    244   class control_block {
    245     unsigned count;
    246   public:
    247     control_block() : count(0) {}
    248     void retain() { ++count; }
    249     int release() { return --count; }
    250   };
    251 
    252   template <typename T>
    253   class shared_ptr {
    254     T *p;
    255     control_block *control;
    256 
    257   public:
    258     shared_ptr() : p(0), control(0) {}
    259     explicit shared_ptr(T *p) : p(p), control(new control_block) {
    260       control->retain();
    261     }
    262     shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
    263       if (control)
    264           control->retain();
    265     }
    266     ~shared_ptr() {
    267       if (control && control->release() == 0) {
    268         delete p;
    269         delete control;
    270       }
    271     };
    272 
    273     T &operator *() {
    274       return *p;
    275     };
    276 
    277     void swap(shared_ptr &other) {
    278       T *tmp = p;
    279       p = other.p;
    280       other.p = tmp;
    281 
    282       control_block *ctrlTmp = control;
    283       control = other.control;
    284       other.control = ctrlTmp;
    285     }
    286   };
    287 
    288   void testSingle() {
    289     shared_ptr<int> a(new int);
    290     *a = 1;
    291   }
    292 
    293   void testDouble() {
    294     shared_ptr<int> a(new int);
    295     shared_ptr<int> b = a;
    296     *a = 1;
    297   }
    298 
    299   void testInvalidated() {
    300     shared_ptr<int> a(new int);
    301     shared_ptr<int> b = a;
    302     *a = 1;
    303 
    304     extern void use(shared_ptr<int> &);
    305     use(b);
    306   }
    307 
    308   void testNestedScope() {
    309     shared_ptr<int> a(new int);
    310     {
    311       shared_ptr<int> b = a;
    312     }
    313     *a = 1;
    314   }
    315 
    316   void testSwap() {
    317     shared_ptr<int> a(new int);
    318     shared_ptr<int> b;
    319     shared_ptr<int> c = a;
    320     shared_ptr<int>(c).swap(b);
    321   }
    322 
    323   void testUseAfterFree() {
    324     int *p = new int;
    325     {
    326       shared_ptr<int> a(p);
    327       shared_ptr<int> b = a;
    328     }
    329 
    330     // FIXME: We should get a warning here, but we don't because we've
    331     // conservatively modeled ~shared_ptr.
    332     *p = 1;
    333   }
    334 }
    335 
    336 // Test double delete
    337 class DerefClass{
    338 public:
    339   int *x;
    340   DerefClass() {}
    341   ~DerefClass() {*x = 1;}
    342 };
    343 
    344 void testDoubleDeleteClassInstance() {
    345   DerefClass *foo = new DerefClass();
    346   delete foo;
    347   delete foo; // expected-warning {{Attempt to delete released memory}}
    348 }
    349 
    350 class EmptyClass{
    351 public:
    352   EmptyClass() {}
    353   ~EmptyClass() {}
    354 };
    355 
    356 void testDoubleDeleteEmptyClass() {
    357   EmptyClass *foo = new EmptyClass();
    358   delete foo;
    359   delete foo;  // expected-warning {{Attempt to delete released memory}}
    360 }
    361