Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
      2 
      3 void clang_analyzer_eval(bool);
      4 void clang_analyzer_checkInlined(bool);
      5 
      6 class A {
      7 public:
      8   ~A() {
      9     int *x = 0;
     10     *x = 3; // expected-warning{{Dereference of null pointer}}
     11   }
     12 };
     13 
     14 int main() {
     15   A a;
     16 }
     17 
     18 
     19 typedef __typeof(sizeof(int)) size_t;
     20 void *malloc(size_t);
     21 void free(void *);
     22 
     23 class SmartPointer {
     24   void *X;
     25 public:
     26   SmartPointer(void *x) : X(x) {}
     27   ~SmartPointer() {
     28     free(X);
     29   }
     30 };
     31 
     32 void testSmartPointer() {
     33   char *mem = (char*)malloc(4);
     34   {
     35     SmartPointer Deleter(mem);
     36     // destructor called here
     37   }
     38   *mem = 0; // expected-warning{{Use of memory after it is freed}}
     39 }
     40 
     41 
     42 void doSomething();
     43 void testSmartPointer2() {
     44   char *mem = (char*)malloc(4);
     45   {
     46     SmartPointer Deleter(mem);
     47     // Remove dead bindings...
     48     doSomething();
     49     // destructor called here
     50   }
     51   *mem = 0; // expected-warning{{Use of memory after it is freed}}
     52 }
     53 
     54 
     55 class Subclass : public SmartPointer {
     56 public:
     57   Subclass(void *x) : SmartPointer(x) {}
     58 };
     59 
     60 void testSubclassSmartPointer() {
     61   char *mem = (char*)malloc(4);
     62   {
     63     Subclass Deleter(mem);
     64     // Remove dead bindings...
     65     doSomething();
     66     // destructor called here
     67   }
     68   *mem = 0; // expected-warning{{Use of memory after it is freed}}
     69 }
     70 
     71 
     72 class MultipleInheritance : public Subclass, public SmartPointer {
     73 public:
     74   MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
     75 };
     76 
     77 void testMultipleInheritance1() {
     78   char *mem = (char*)malloc(4);
     79   {
     80     MultipleInheritance Deleter(mem, 0);
     81     // Remove dead bindings...
     82     doSomething();
     83     // destructor called here
     84   }
     85   *mem = 0; // expected-warning{{Use of memory after it is freed}}
     86 }
     87 
     88 void testMultipleInheritance2() {
     89   char *mem = (char*)malloc(4);
     90   {
     91     MultipleInheritance Deleter(0, mem);
     92     // Remove dead bindings...
     93     doSomething();
     94     // destructor called here
     95   }
     96   *mem = 0; // expected-warning{{Use of memory after it is freed}}
     97 }
     98 
     99 void testMultipleInheritance3() {
    100   char *mem = (char*)malloc(4);
    101   {
    102     MultipleInheritance Deleter(mem, mem);
    103     // Remove dead bindings...
    104     doSomething();
    105     // destructor called here
    106     // expected-warning@28 {{Attempt to free released memory}}
    107   }
    108 }
    109 
    110 
    111 class SmartPointerMember {
    112   SmartPointer P;
    113 public:
    114   SmartPointerMember(void *x) : P(x) {}
    115 };
    116 
    117 void testSmartPointerMember() {
    118   char *mem = (char*)malloc(4);
    119   {
    120     SmartPointerMember Deleter(mem);
    121     // Remove dead bindings...
    122     doSomething();
    123     // destructor called here
    124   }
    125   *mem = 0; // expected-warning{{Use of memory after it is freed}}
    126 }
    127 
    128 
    129 struct IntWrapper {
    130   IntWrapper() : x(0) {}
    131   ~IntWrapper();
    132   int *x;
    133 };
    134 
    135 void testArrayInvalidation() {
    136   int i = 42;
    137   int j = 42;
    138 
    139   {
    140     IntWrapper arr[2];
    141 
    142     // There should be no undefined value warnings here.
    143     // Eventually these should be TRUE as well, but right now
    144     // we can't handle array constructors.
    145     clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
    146     clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
    147 
    148     arr[0].x = &i;
    149     arr[1].x = &j;
    150     clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
    151     clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
    152   }
    153 
    154   // The destructors should have invalidated i and j.
    155   clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
    156   clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
    157 }
    158 
    159 
    160 
    161 // Don't crash on a default argument inside an initializer.
    162 struct DefaultArg {
    163   DefaultArg(int x = 0) {}
    164   ~DefaultArg();
    165 };
    166 
    167 struct InheritsDefaultArg : DefaultArg {
    168   InheritsDefaultArg() {}
    169   virtual ~InheritsDefaultArg();
    170 };
    171 
    172 void testDefaultArg() {
    173   InheritsDefaultArg a;
    174   // Force a bug to be emitted.
    175   *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
    176 }
    177 
    178 
    179 namespace DestructorVirtualCalls {
    180   class A {
    181   public:
    182     int *out1, *out2, *out3;
    183 
    184     virtual int get() { return 1; }
    185 
    186     ~A() {
    187       *out1 = get();
    188     }
    189   };
    190 
    191   class B : public A {
    192   public:
    193     virtual int get() { return 2; }
    194 
    195     ~B() {
    196       *out2 = get();
    197     }
    198   };
    199 
    200   class C : public B {
    201   public:
    202     virtual int get() { return 3; }
    203 
    204     ~C() {
    205       *out3 = get();
    206     }
    207   };
    208 
    209   void test() {
    210     int a, b, c;
    211 
    212     // New scope for the C object.
    213     {
    214       C obj;
    215       clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
    216 
    217       // Sanity check for devirtualization.
    218       A *base = &obj;
    219       clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
    220 
    221       obj.out1 = &a;
    222       obj.out2 = &b;
    223       obj.out3 = &c;
    224     }
    225 
    226     clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
    227     clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
    228     clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
    229   }
    230 }
    231 
    232 
    233 namespace DestructorsShouldNotAffectReturnValues {
    234   class Dtor {
    235   public:
    236     ~Dtor() {
    237       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    238     }
    239   };
    240 
    241   void *allocate() {
    242     Dtor d;
    243     return malloc(4); // no-warning
    244   }
    245 
    246   void test() {
    247     // At one point we had an issue where the statements inside an
    248     // inlined destructor kept us from finding the return statement,
    249     // leading the analyzer to believe that the malloc'd memory had leaked.
    250     void *p = allocate();
    251     free(p); // no-warning
    252   }
    253 }
    254 
    255 namespace MultipleInheritanceVirtualDtors {
    256   class VirtualDtor {
    257   protected:
    258     virtual ~VirtualDtor() {
    259       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    260     }
    261   };
    262 
    263   class NonVirtualDtor {
    264   protected:
    265     ~NonVirtualDtor() {
    266       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    267     }
    268   };
    269 
    270   class SubclassA : public VirtualDtor, public NonVirtualDtor {
    271   public:
    272     virtual ~SubclassA() {}
    273   };
    274   class SubclassB : public NonVirtualDtor, public VirtualDtor {
    275   public:
    276     virtual ~SubclassB() {}
    277   };
    278 
    279   void test() {
    280     SubclassA a;
    281     SubclassB b;
    282   }
    283 }
    284 
    285 namespace ExplicitDestructorCall {
    286   class VirtualDtor {
    287   public:
    288     virtual ~VirtualDtor() {
    289       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    290     }
    291   };
    292 
    293   class Subclass : public VirtualDtor {
    294   public:
    295     virtual ~Subclass() {
    296       clang_analyzer_checkInlined(false); // no-warning
    297     }
    298   };
    299 
    300   void destroy(Subclass *obj) {
    301     obj->VirtualDtor::~VirtualDtor();
    302   }
    303 }
    304 
    305 
    306 namespace MultidimensionalArrays {
    307   void testArrayInvalidation() {
    308     int i = 42;
    309     int j = 42;
    310 
    311     {
    312       IntWrapper arr[2][2];
    313 
    314       // There should be no undefined value warnings here.
    315       // Eventually these should be TRUE as well, but right now
    316       // we can't handle array constructors.
    317       clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}}
    318       clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}}
    319 
    320       arr[0][0].x = &i;
    321       arr[1][1].x = &j;
    322       clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
    323       clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
    324     }
    325 
    326     // The destructors should have invalidated i and j.
    327     clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
    328     clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
    329   }
    330 }
    331