1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,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 testDoubleDelete() {
148   int *p = new int;
149   delete p;
150   delete p; // expected-warning{{Attempt to free released memory}}
151 }
152 
153 void testExprDeleteArg() {
154   int i;
155   delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
156 }
157 
158 void testExprDeleteArrArg() {
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 testAllocDeallocNames() {
164   int *p = new(std::nothrow) int[1];
165   delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
166 }
167 
168 //--------------------------------
169 // Test escape of newed const pointer. Note, a const pointer can be deleted.
170 //--------------------------------
171 struct StWithConstPtr {
172   const int *memp;
173 };
174 void escape(const int &x);
175 void escapeStruct(const StWithConstPtr &x);
176 void escapePtr(const StWithConstPtr *x);
177 void escapeVoidPtr(const void *x);
178 
179 void testConstEscape() {
180   int *p = new int(1);
181   escape(*p);
182 } // no-warning
183 
184 void testConstEscapeStruct() {
185   StWithConstPtr *St = new StWithConstPtr();
186   escapeStruct(*St);
187 } // no-warning
188 
189 void testConstEscapeStructPtr() {
190   StWithConstPtr *St = new StWithConstPtr();
191   escapePtr(St);
192 } // no-warning
193 
194 void testConstEscapeMember() {
195   StWithConstPtr St;
196   St.memp = new int(2);
197   escapeVoidPtr(St.memp);
198 } // no-warning
199 
200 void testConstEscapePlacementNew() {
201   int *x = (int *)malloc(sizeof(int));
202   void *y = new (x) int;
203   escapeVoidPtr(y);
204 } // no-warning
205 
206 //============== Test Uninitialized delete delete[]========================
207 void testUninitDelete() {
208   int *x;
209   int * y = new int;
210   delete y;
211   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
212 }
213 
214 void testUninitDeleteArray() {
215   int *x;
216   int * y = new int[5];
217   delete[] y;
218   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
219 }
220 
221 void testUninitFree() {
222   int *x;
223   free(x); // expected-warning{{Function call argument is an uninitialized value}}
224 }
225 
226 void testUninitDeleteSink() {
227   int *x;
228   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
229   (*(volatile int *)0 = 1); // no warn
230 }
231 
232 void testUninitDeleteArraySink() {
233   int *x;
234   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
235   (*(volatile int *)0 = 1); // no warn
236 }
237 
238 namespace reference_count {
239   class control_block {
240     unsigned count;
241   public:
242     control_block() : count(0) {}
243     void retain() { ++count; }
244     int release() { return --count; }
245   };
246 
247   template <typename T>
248   class shared_ptr {
249     T *p;
250     control_block *control;
251 
252   public:
253     shared_ptr() : p(0), control(0) {}
254     explicit shared_ptr(T *p) : p(p), control(new control_block) {
255       control->retain();
256     }
257     shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
258       if (control)
259           control->retain();
260     }
261     ~shared_ptr() {
262       if (control && control->release() == 0) {
263         delete p;
264         delete control;
265       }
266     };
267 
268     T &operator *() {
269       return *p;
270     };
271 
272     void swap(shared_ptr &other) {
273       T *tmp = p;
274       p = other.p;
275       other.p = tmp;
276 
277       control_block *ctrlTmp = control;
278       control = other.control;
279       other.control = ctrlTmp;
280     }
281   };
282 
283   void testSingle() {
284     shared_ptr<int> a(new int);
285     *a = 1;
286   }
287 
288   void testDouble() {
289     shared_ptr<int> a(new int);
290     shared_ptr<int> b = a;
291     *a = 1;
292   }
293 
294   void testInvalidated() {
295     shared_ptr<int> a(new int);
296     shared_ptr<int> b = a;
297     *a = 1;
298 
299     extern void use(shared_ptr<int> &);
300     use(b);
301   }
302 
303   void testNestedScope() {
304     shared_ptr<int> a(new int);
305     {
306       shared_ptr<int> b = a;
307     }
308     *a = 1;
309   }
310 
311   void testSwap() {
312     shared_ptr<int> a(new int);
313     shared_ptr<int> b;
314     shared_ptr<int> c = a;
315     shared_ptr<int>(c).swap(b);
316   }
317 
318   void testUseAfterFree() {
319     int *p = new int;
320     {
321       shared_ptr<int> a(p);
322       shared_ptr<int> b = a;
323     }
324 
325     // FIXME: We should get a warning here, but we don't because we've
326     // conservatively modeled ~shared_ptr.
327     *p = 1;
328   }
329 }
330 
331 // Test double delete
332 class DerefClass{
333 public:
334   int *x;
335   DerefClass() {}
336   ~DerefClass() {*x = 1;}
337 };
338 
339 void testDoubleDeleteClassInstance() {
340   DerefClass *foo = new DerefClass();
341   delete foo;
342   delete foo; // expected-warning {{Attempt to delete released memory}}
343 }
344 
345 class EmptyClass{
346 public:
347   EmptyClass() {}
348   ~EmptyClass() {}
349 };
350 
351 void testDoubleDeleteEmptyClass() {
352   EmptyClass *foo = new EmptyClass();
353   delete foo;
354   delete foo;  // expected-warning {{Attempt to delete released memory}}
355 }
356