• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~A()8   ~A() {
9     int *x = 0;
10     *x = 3; // expected-warning{{Dereference of null pointer}}
11   }
12 };
13 
main()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:
SmartPointer(void * x)26   SmartPointer(void *x) : X(x) {}
~SmartPointer()27   ~SmartPointer() {
28     free(X);
29   }
30 };
31 
testSmartPointer()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();
testSmartPointer2()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:
Subclass(void * x)57   Subclass(void *x) : SmartPointer(x) {}
58 };
59 
testSubclassSmartPointer()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:
MultipleInheritance(void * a,void * b)74   MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
75 };
76 
testMultipleInheritance1()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 
testMultipleInheritance2()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 
testMultipleInheritance3()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:
SmartPointerMember(void * x)114   SmartPointerMember(void *x) : P(x) {}
115 };
116 
testSmartPointerMember()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 {
IntWrapperIntWrapper130   IntWrapper() : x(0) {}
131   ~IntWrapper();
132   int *x;
133 };
134 
testArrayInvalidation()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 {
DefaultArgDefaultArg163   DefaultArg(int x = 0) {}
164   ~DefaultArg();
165 };
166 
167 struct InheritsDefaultArg : DefaultArg {
InheritsDefaultArgInheritsDefaultArg168   InheritsDefaultArg() {}
169   virtual ~InheritsDefaultArg();
170 };
171 
testDefaultArg()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 
get()184     virtual int get() { return 1; }
185 
~A()186     ~A() {
187       *out1 = get();
188     }
189   };
190 
191   class B : public A {
192   public:
get()193     virtual int get() { return 2; }
194 
~B()195     ~B() {
196       *out2 = get();
197     }
198   };
199 
200   class C : public B {
201   public:
get()202     virtual int get() { return 3; }
203 
~C()204     ~C() {
205       *out3 = get();
206     }
207   };
208 
test()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:
~Dtor()236     ~Dtor() {
237       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
238     }
239   };
240 
allocate()241   void *allocate() {
242     Dtor d;
243     return malloc(4); // no-warning
244   }
245 
test()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:
~VirtualDtor()258     virtual ~VirtualDtor() {
259       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
260     }
261   };
262 
263   class NonVirtualDtor {
264   protected:
~NonVirtualDtor()265     ~NonVirtualDtor() {
266       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
267     }
268   };
269 
270   class SubclassA : public VirtualDtor, public NonVirtualDtor {
271   public:
~SubclassA()272     virtual ~SubclassA() {}
273   };
274   class SubclassB : public NonVirtualDtor, public VirtualDtor {
275   public:
~SubclassB()276     virtual ~SubclassB() {}
277   };
278 
test()279   void test() {
280     SubclassA a;
281     SubclassB b;
282   }
283 }
284 
285 namespace ExplicitDestructorCall {
286   class VirtualDtor {
287   public:
~VirtualDtor()288     virtual ~VirtualDtor() {
289       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
290     }
291   };
292 
293   class Subclass : public VirtualDtor {
294   public:
~Subclass()295     virtual ~Subclass() {
296       clang_analyzer_checkInlined(false); // no-warning
297     }
298   };
299 
destroy(Subclass * obj)300   void destroy(Subclass *obj) {
301     obj->VirtualDtor::~VirtualDtor();
302   }
303 }
304 
305 
306 namespace MultidimensionalArrays {
testArrayInvalidation()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;
IntWrapperLifetimeExtension::IntWrapper335 	IntWrapper(int y) : x(y) {}
IntWrapperLifetimeExtension::IntWrapper336 	IntWrapper() {
337       extern void use(int);
338       use(x); // no-warning
339 	}
340   };
341 
342   struct DerivedWrapper : public IntWrapper {
DerivedWrapperLifetimeExtension::DerivedWrapper343 	DerivedWrapper(int y) : IntWrapper(y) {}
344   };
345 
get()346   DerivedWrapper get() {
347 	return DerivedWrapper(1);
348   }
349 
test()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();
~SaveOnDestruct()361     ~SaveOnDestruct() {
362       lastOutput = value;
363     }
364   };
365 
testSimple()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_;
NRCheckLifetimeExtension::NRCheck379     NRCheck():bool_(true) {}
380     ~NRCheck() __attribute__((noreturn));
operator boolLifetimeExtension::NRCheck381     operator bool() const { return bool_; }
382   };
383 
384   struct CheckAutoDestructor {
385     bool bool_;
CheckAutoDestructorLifetimeExtension::CheckAutoDestructor386     CheckAutoDestructor():bool_(true) {}
operator boolLifetimeExtension::CheckAutoDestructor387     operator bool() const { return bool_; }
388   };
389 
390   struct CheckCustomDestructor {
391     bool bool_;
CheckCustomDestructorLifetimeExtension::CheckCustomDestructor392     CheckCustomDestructor():bool_(true) {}
393     ~CheckCustomDestructor();
operator boolLifetimeExtension::CheckCustomDestructor394     operator bool() const { return bool_; }
395   };
396 
testUnnamedNR()397   bool testUnnamedNR() {
398     if (NRCheck())
399       return true;
400     return false;
401   }
402 
testNamedNR()403   bool testNamedNR() {
404     if (NRCheck c = NRCheck())
405       return true;
406     return false;
407   }
408 
testUnnamedAutoDestructor()409   bool testUnnamedAutoDestructor() {
410     if (CheckAutoDestructor())
411       return true;
412     return false;
413   }
414 
testNamedAutoDestructor()415   bool testNamedAutoDestructor() {
416     if (CheckAutoDestructor c = CheckAutoDestructor())
417       return true;
418     return false;
419   }
420 
testUnnamedCustomDestructor()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
testNamedCustomDestructor()429   bool testNamedCustomDestructor() {
430     if (CheckCustomDestructor c = CheckCustomDestructor())
431       return true;
432     return false;
433   }
434 
testMultipleTemporariesCustomDestructor()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;
~VirtualDtorBase()444     virtual ~VirtualDtorBase() {}
445   };
446 
447   class SaveOnVirtualDestruct : public VirtualDtorBase {
448   public:
449     static int lastOutput;
450 
451     SaveOnVirtualDestruct();
~SaveOnVirtualDestruct()452     virtual ~SaveOnVirtualDestruct() {
453       lastOutput = value;
454     }
455   };
456 
testVirtual()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 
f(int ** x)474   void f(int **x) {
475     NR nr;
476   }
477 
g()478   void g() {
479     int *x;
480     f(&x);
481     *x = 47; // no warning
482   }
483 
g2(int * x)484   void g2(int *x) {
485     if (! x) NR();
486     *x = 47; // no warning
487   }
488 }
489 
490 namespace PseudoDtor {
491   template <typename T>
destroy(T & obj)492   void destroy(T &obj) {
493     clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
494     obj.~T();
495   }
496 
test()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}}
f(Foo * foo)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>
do_copy(T * dest,const U * src,unsigned count)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;
NonTrivialTypeTraitExpr::NonTrivial521   NonTrivial() : p(new int[1]) { p[0] = 0; }
NonTrivialTypeTraitExpr::NonTrivial522   NonTrivial(const NonTrivial &other) {
523     p = new int[1];
524     do_copy(p, other.p, 1);
525   }
operator =TypeTraitExpr::NonTrivial526   NonTrivial &operator=(const NonTrivial &other) {
527     p = other.p;
528     return *this;
529   }
~NonTrivialTypeTraitExpr::NonTrivial530   ~NonTrivial() {
531     delete[] p; // expected-warning {{free released memory}}
532   }
533 };
534 
f()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