xref: /llvm-project/clang/test/Analysis/NewDelete-checker-test.cpp (revision 339282d49f5310a2837da45c0ccc19da15675554)
1 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \
2 // RUN:   -verify=expected,newdelete \
3 // RUN:   -analyzer-checker=core \
4 // RUN:   -analyzer-checker=cplusplus.NewDelete
5 //
6 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks %s \
7 // RUN:   -verify=expected,newdelete,leak \
8 // RUN:   -analyzer-checker=core \
9 // RUN:   -analyzer-checker=cplusplus.NewDelete \
10 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
11 //
12 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
13 // RUN:   -verify=expected,leak \
14 // RUN:   -analyzer-checker=core \
15 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
16 //
17 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks %s \
18 // RUN:   -verify=expected,newdelete \
19 // RUN:   -analyzer-checker=core \
20 // RUN:   -analyzer-checker=cplusplus.NewDelete
21 //
22 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++17 -fblocks %s \
23 // RUN:   -verify=expected,newdelete,leak \
24 // RUN:   -analyzer-checker=core \
25 // RUN:   -analyzer-checker=cplusplus.NewDelete \
26 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
27 //
28 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \
29 // RUN:   -verify=expected,leak \
30 // RUN:   -analyzer-checker=core \
31 // RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
32 
33 #include "Inputs/system-header-simulator-cxx.h"
34 
35 typedef __typeof__(sizeof(int)) size_t;
36 extern "C" void *malloc(size_t);
37 extern "C" void free (void* ptr);
38 int *global;
39 
40 //----- Standard non-placement operators
41 void testGlobalOpNew() {
42   void *p = operator new(0);
43 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
44 
45 void testGlobalOpNewArray() {
46   void *p = operator new[](0);
47 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
48 
49 void testGlobalNewExpr() {
50   int *p = new int;
51 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
52 
53 void testGlobalNewExprArray() {
54   int *p = new int[0];
55 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
56 
57 //----- Standard nothrow placement operators
58 void testGlobalNoThrowPlacementOpNewBeforeOverload() {
59   void *p = operator new(0, std::nothrow);
60 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
61 
62 void testGlobalNoThrowPlacementExprNewBeforeOverload() {
63   int *p = new(std::nothrow) int;
64 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
65 
66 //----- Other cases
67 void testNewMemoryIsInHeap() {
68   int *p = new int;
69   if (global != p) // condition is always true as 'p' wraps a heap region that
70                    // is different from a region wrapped by 'global'
71     global = p; // pointer escapes
72 }
73 
74 struct PtrWrapper {
75   int *x;
76 
77   PtrWrapper(int *input) : x(input) {}
78 };
79 
80 void testNewInvalidationPlacement(PtrWrapper *w) {
81   // Ensure that we don't consider this a leak.
82   new (w) PtrWrapper(new int); // no warn
83 }
84 
85 //-----------------------------------------
86 // check for usage of zero-allocated memory
87 //-----------------------------------------
88 
89 void testUseZeroAlloc1() {
90   int *p = (int *)operator new(0);
91   *p = 1; // newdelete-warning {{Use of memory allocated with size zero}}
92   delete p;
93 }
94 
95 int testUseZeroAlloc2() {
96   int *p = (int *)operator new[](0);
97   return p[0]; // newdelete-warning {{Use of memory allocated with size zero}}
98   delete[] p;
99 }
100 
101 void f(int);
102 
103 void testUseZeroAlloc3() {
104   int *p = new int[0];
105   f(*p); // newdelete-warning {{Use of memory allocated with size zero}}
106   delete[] p;
107 }
108 
109 //---------------
110 // other checks
111 //---------------
112 
113 class SomeClass {
114 public:
115   void f(int *p);
116 };
117 
118 void f(int *p1, int *p2 = 0, int *p3 = 0);
119 void g(SomeClass &c, ...);
120 
121 void testUseFirstArgAfterDelete() {
122   int *p = new int;
123   delete p;
124   f(p); // newdelete-warning{{Use of memory after it is freed}}
125 }
126 
127 void testUseMiddleArgAfterDelete(int *p) {
128   delete p;
129   f(0, p); // newdelete-warning{{Use of memory after it is freed}}
130 }
131 
132 void testUseLastArgAfterDelete(int *p) {
133   delete p;
134   f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}}
135 }
136 
137 void testUseSeveralArgsAfterDelete(int *p) {
138   delete p;
139   f(p, p, p); // newdelete-warning{{Use of memory after it is freed}}
140 }
141 
142 void testUseRefArgAfterDelete(SomeClass &c) {
143   delete &c;
144   g(c); // newdelete-warning{{Use of memory after it is freed}}
145 }
146 
147 void testVariadicArgAfterDelete() {
148   SomeClass c;
149   int *p = new int;
150   delete p;
151   g(c, 0, p); // newdelete-warning{{Use of memory after it is freed}}
152 }
153 
154 void testUseMethodArgAfterDelete(int *p) {
155   SomeClass *c = new SomeClass;
156   delete p;
157   c->f(p); // newdelete-warning{{Use of memory after it is freed}}
158 }
159 
160 void testUseThisAfterDelete() {
161   SomeClass *c = new SomeClass;
162   delete c;
163   c->f(0); // newdelete-warning{{Use of memory after it is freed}}
164 }
165 
166 void testDoubleDelete() {
167   int *p = new int;
168   delete p;
169   delete p; // newdelete-warning{{Attempt to free released memory}}
170 }
171 
172 void testExprDeleteArg() {
173   int i;
174   delete &i; // newdelete-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
175 }
176 
177 void testExprDeleteArrArg() {
178   int i;
179   delete[] & i; // newdelete-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
180 }
181 
182 void testAllocDeallocNames() {
183   int *p = new(std::nothrow) int[1];
184   delete[] (++p);
185   // newdelete-warning@-1{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
186 }
187 
188 //--------------------------------
189 // Test escape of newed const pointer. Note, a const pointer can be deleted.
190 //--------------------------------
191 struct StWithConstPtr {
192   const int *memp;
193 };
194 void escape(const int &x);
195 void escapeStruct(const StWithConstPtr &x);
196 void escapePtr(const StWithConstPtr *x);
197 void escapeVoidPtr(const void *x);
198 
199 void testConstEscape() {
200   int *p = new int(1);
201   escape(*p);
202 } // no-warning
203 
204 void testConstEscapeStruct() {
205   StWithConstPtr *St = new StWithConstPtr();
206   escapeStruct(*St);
207 } // no-warning
208 
209 void testConstEscapeStructPtr() {
210   StWithConstPtr *St = new StWithConstPtr();
211   escapePtr(St);
212 } // no-warning
213 
214 void testConstEscapeMember() {
215   StWithConstPtr St;
216   St.memp = new int(2);
217   escapeVoidPtr(St.memp);
218 } // no-warning
219 
220 void testConstEscapePlacementNew() {
221   int *x = (int *)malloc(sizeof(int));
222   void *y = new (x) int;
223   escapeVoidPtr(y);
224 } // no-warning
225 
226 //============== Test Uninitialized delete delete[]========================
227 void testUninitDelete() {
228   int *x;
229   int * y = new int;
230   delete y;
231   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
232 }
233 
234 void testUninitDeleteArray() {
235   int *x;
236   int * y = new int[5];
237   delete[] y;
238   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
239 }
240 
241 void testUninitFree() {
242   int *x;
243   free(x); // expected-warning{{1st function call argument is an uninitialized value}}
244 }
245 
246 void testUninitDeleteSink() {
247   int *x;
248   delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
249   (*(volatile int *)0 = 1); // no warn
250 }
251 
252 void testUninitDeleteArraySink() {
253   int *x;
254   delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
255   (*(volatile int *)0 = 1); // no warn
256 }
257 
258 namespace reference_count {
259   class control_block {
260     unsigned count;
261   public:
262     control_block() : count(0) {}
263     void retain() { ++count; }
264     int release() { return --count; }
265   };
266 
267   template <typename T>
268   class shared_ptr {
269     T *p;
270     control_block *control;
271 
272   public:
273     shared_ptr() : p(0), control(0) {}
274     explicit shared_ptr(T *p) : p(p), control(new control_block) {
275       control->retain();
276     }
277     shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) {
278       if (control)
279           control->retain();
280     }
281     ~shared_ptr() {
282       if (control && control->release() == 0) {
283         delete p;
284         delete control;
285       }
286     };
287 
288     T &operator *() {
289       return *p;
290     };
291 
292     void swap(shared_ptr &other) {
293       T *tmp = p;
294       p = other.p;
295       other.p = tmp;
296 
297       control_block *ctrlTmp = control;
298       control = other.control;
299       other.control = ctrlTmp;
300     }
301   };
302 
303   template <typename T, typename... Args>
304   shared_ptr<T> make_shared(Args &&...args) {
305     return shared_ptr<T>(new T(static_cast<Args &&>(args)...));
306   }
307 
308   void testSingle() {
309     shared_ptr<int> a(new int);
310     *a = 1;
311   }
312 
313   void testMake() {
314     shared_ptr<int> a = make_shared<int>();
315     *a = 1;
316   }
317 
318   void testMakeInParens() {
319     shared_ptr<int> a = (make_shared<int>()); // no warn
320     *a = 1;
321   }
322 
323   void testDouble() {
324     shared_ptr<int> a(new int);
325     shared_ptr<int> b = a;
326     *a = 1;
327   }
328 
329   void testInvalidated() {
330     shared_ptr<int> a(new int);
331     shared_ptr<int> b = a;
332     *a = 1;
333 
334     extern void use(shared_ptr<int> &);
335     use(b);
336   }
337 
338   void testNestedScope() {
339     shared_ptr<int> a(new int);
340     {
341       shared_ptr<int> b = a;
342     }
343     *a = 1;
344   }
345 
346   void testSwap() {
347     shared_ptr<int> a(new int);
348     shared_ptr<int> b;
349     shared_ptr<int> c = a;
350     shared_ptr<int>(c).swap(b);
351   }
352 
353   void testUseAfterFree() {
354     int *p = new int;
355     {
356       shared_ptr<int> a(p);
357       shared_ptr<int> b = a;
358     }
359 
360     // FIXME: We should get a warning here, but we don't because we've
361     // conservatively modeled ~shared_ptr.
362     *p = 1;
363   }
364 }
365 
366 // Test double delete
367 class DerefClass{
368 public:
369   int *x;
370   DerefClass() {}
371   ~DerefClass() {
372     int i = 0;
373     x = &i;
374     *x = 1;
375   }
376 };
377 
378 void testDoubleDeleteClassInstance() {
379   DerefClass *foo = new DerefClass();
380   delete foo;
381   delete foo; // newdelete-warning {{Attempt to delete released memory}}
382 }
383 
384 class EmptyClass{
385 public:
386   EmptyClass() {}
387   ~EmptyClass() {}
388 };
389 
390 void testDoubleDeleteEmptyClass() {
391   EmptyClass *foo = new EmptyClass();
392   delete foo;
393   delete foo; // newdelete-warning {{Attempt to delete released memory}}
394 }
395 
396 struct Base {
397   virtual ~Base() {}
398 };
399 
400 struct Derived : Base {
401 };
402 
403 Base *allocate() {
404   return new Derived;
405 }
406 
407 void shouldNotReportLeak() {
408   Derived *p = (Derived *)allocate();
409   delete p;
410 }
411 
412 template<void *allocate_fn(size_t)>
413 void* allocate_via_nttp(size_t n) {
414   return allocate_fn(n);
415 }
416 
417 template<void deallocate_fn(void*)>
418 void deallocate_via_nttp(void* ptr) {
419   deallocate_fn(ptr);
420 }
421 
422 void testNTTPNewNTTPDelete() {
423   void* p = allocate_via_nttp<::operator new>(10);
424   deallocate_via_nttp<::operator delete>(p);
425 } // no warn
426 
427 void testNTTPNewDirectDelete() {
428   void* p = allocate_via_nttp<::operator new>(10);
429   ::operator delete(p);
430 } // no warn
431 
432 void testDirectNewNTTPDelete() {
433   void* p = ::operator new(10);
434   deallocate_via_nttp<::operator delete>(p);
435 }
436 
437 void not_free(void*) {
438 }
439 
440 void testLeakBecauseNTTPIsNotDeallocation() {
441   void* p = ::operator new(10);
442   deallocate_via_nttp<not_free>(p);
443 }  // leak-warning{{Potential leak of memory pointed to by 'p'}}
444