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