Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -Wno-inaccessible-base -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 
    332 namespace LifetimeExtension {
    333   struct IntWrapper {
    334 	int x;
    335 	IntWrapper(int y) : x(y) {}
    336 	IntWrapper() {
    337       extern void use(int);
    338       use(x); // no-warning
    339 	}
    340   };
    341 
    342   struct DerivedWrapper : public IntWrapper {
    343 	DerivedWrapper(int y) : IntWrapper(y) {}
    344   };
    345 
    346   DerivedWrapper get() {
    347 	return DerivedWrapper(1);
    348   }
    349 
    350   void test() {
    351 	const DerivedWrapper &d = get(); // lifetime extended here
    352   }
    353 
    354 
    355   class SaveOnDestruct {
    356   public:
    357     static int lastOutput;
    358     int value;
    359 
    360     SaveOnDestruct();
    361     ~SaveOnDestruct() {
    362       lastOutput = value;
    363     }
    364   };
    365 
    366   void testSimple() {
    367     {
    368       const SaveOnDestruct &obj = SaveOnDestruct();
    369       if (obj.value != 42)
    370         return;
    371       // destructor called here
    372     }
    373 
    374     clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
    375   }
    376 
    377   struct NRCheck {
    378     bool bool_;
    379     NRCheck():bool_(true) {}
    380     ~NRCheck() __attribute__((noreturn));
    381     operator bool() const { return bool_; }
    382   };
    383 
    384   struct CheckAutoDestructor {
    385     bool bool_;
    386     CheckAutoDestructor():bool_(true) {}
    387     operator bool() const { return bool_; }
    388   };
    389 
    390   struct CheckCustomDestructor {
    391     bool bool_;
    392     CheckCustomDestructor():bool_(true) {}
    393     ~CheckCustomDestructor();
    394     operator bool() const { return bool_; }
    395   };
    396 
    397   bool testUnnamedNR() {
    398     if (NRCheck())
    399       return true;
    400     return false;
    401   }
    402 
    403   bool testNamedNR() {
    404     if (NRCheck c = NRCheck())
    405       return true;
    406     return false;
    407   }
    408 
    409   bool testUnnamedAutoDestructor() {
    410     if (CheckAutoDestructor())
    411       return true;
    412     return false;
    413   }
    414 
    415   bool testNamedAutoDestructor() {
    416     if (CheckAutoDestructor c = CheckAutoDestructor())
    417       return true;
    418     return false;
    419   }
    420 
    421   bool testUnnamedCustomDestructor() {
    422     if (CheckCustomDestructor())
    423       return true;
    424     return false;
    425   }
    426 
    427   // This case used to cause an unexpected "Undefined or garbage value returned
    428   // to caller" warning
    429   bool testNamedCustomDestructor() {
    430     if (CheckCustomDestructor c = CheckCustomDestructor())
    431       return true;
    432     return false;
    433   }
    434 
    435   bool testMultipleTemporariesCustomDestructor() {
    436     if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
    437       return true;
    438     return false;
    439   }
    440 
    441   class VirtualDtorBase {
    442   public:
    443     int value;
    444     virtual ~VirtualDtorBase() {}
    445   };
    446 
    447   class SaveOnVirtualDestruct : public VirtualDtorBase {
    448   public:
    449     static int lastOutput;
    450 
    451     SaveOnVirtualDestruct();
    452     virtual ~SaveOnVirtualDestruct() {
    453       lastOutput = value;
    454     }
    455   };
    456 
    457   void testVirtual() {
    458     {
    459       const VirtualDtorBase &obj = SaveOnVirtualDestruct();
    460       if (obj.value != 42)
    461         return;
    462       // destructor called here
    463     }
    464 
    465     clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
    466   }
    467 }
    468 
    469 namespace NoReturn {
    470   struct NR {
    471     ~NR() __attribute__((noreturn));
    472   };
    473 
    474   void f(int **x) {
    475     NR nr;
    476   }
    477 
    478   void g() {
    479     int *x;
    480     f(&x);
    481     *x = 47; // no warning
    482   }
    483 
    484   void g2(int *x) {
    485     if (! x) NR();
    486     *x = 47; // no warning
    487   }
    488 }
    489 
    490 namespace PseudoDtor {
    491   template <typename T>
    492   void destroy(T &obj) {
    493     clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    494     obj.~T();
    495   }
    496 
    497   void test() {
    498     int i;
    499     destroy(i);
    500     clang_analyzer_eval(true); // expected-warning{{TRUE}}
    501   }
    502 }
    503 
    504 namespace Incomplete {
    505   class Foo; // expected-note{{forward declaration}}
    506   void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
    507 }
    508 
    509 namespace TypeTraitExpr {
    510 template <bool IsSimple, typename T>
    511 struct copier {
    512   static void do_copy(T *dest, const T *src, unsigned count);
    513 };
    514 template <typename T, typename U>
    515 void do_copy(T *dest, const U *src, unsigned count) {
    516   const bool IsSimple = __is_trivial(T) && __is_same(T, U);
    517   copier<IsSimple, T>::do_copy(dest, src, count);
    518 }
    519 struct NonTrivial {
    520   int *p;
    521   NonTrivial() : p(new int[1]) { p[0] = 0; }
    522   NonTrivial(const NonTrivial &other) {
    523     p = new int[1];
    524     do_copy(p, other.p, 1);
    525   }
    526   NonTrivial &operator=(const NonTrivial &other) {
    527     p = other.p;
    528     return *this;
    529   }
    530   ~NonTrivial() {
    531     delete[] p; // expected-warning {{free released memory}}
    532   }
    533 };
    534 
    535 void f() {
    536   NonTrivial nt1;
    537   NonTrivial nt2(nt1);
    538   nt1 = nt2;
    539   clang_analyzer_eval(__is_trivial(NonTrivial)); // expected-warning{{FALSE}}
    540   clang_analyzer_eval(__alignof(NonTrivial) > 0); // expected-warning{{TRUE}}
    541 }
    542 }
    543