• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~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