[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / test / Analysis / NewDelete-checker-test.cpp
blob1100b49e84d3acd2773f3f80d34f1822dcd0dea3
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
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
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
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
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
33 #include "Inputs/system-header-simulator-cxx.h"
35 typedef __typeof__(sizeof(int)) size_t;
36 extern "C" void *malloc(size_t);
37 extern "C" void free (void* ptr);
38 int *global;
40 //------------------
41 // check for leaks
42 //------------------
44 //----- Standard non-placement operators
45 void testGlobalOpNew() {
46 void *p = operator new(0);
47 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
49 void testGlobalOpNewArray() {
50 void *p = operator new[](0);
51 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
53 void testGlobalNewExpr() {
54 int *p = new int;
55 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
57 void testGlobalNewExprArray() {
58 int *p = new int[0];
59 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
61 //----- Standard nothrow placement operators
62 void testGlobalNoThrowPlacementOpNewBeforeOverload() {
63 void *p = operator new(0, std::nothrow);
64 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
66 void testGlobalNoThrowPlacementExprNewBeforeOverload() {
67 int *p = new(std::nothrow) int;
68 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
70 //----- Standard pointer placement operators
71 void testGlobalPointerPlacementNew() {
72 int i;
74 void *p1 = operator new(0, &i); // no warn
76 void *p2 = operator new[](0, &i); // no warn
78 int *p3 = new(&i) int; // no warn
80 int *p4 = new(&i) int[0]; // no warn
83 //----- Other cases
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
91 struct PtrWrapper {
92 int *x;
94 PtrWrapper(int *input) : x(input) {}
97 void testNewInvalidationPlacement(PtrWrapper *w) {
98 // Ensure that we don't consider this a leak.
99 new (w) PtrWrapper(new int); // no warn
102 //-----------------------------------------
103 // check for usage of zero-allocated memory
104 //-----------------------------------------
106 void testUseZeroAlloc1() {
107 int *p = (int *)operator new(0);
108 *p = 1; // newdelete-warning {{Use of memory allocated with size zero}}
109 delete p;
112 int testUseZeroAlloc2() {
113 int *p = (int *)operator new[](0);
114 return p[0]; // newdelete-warning {{Use of memory allocated with size zero}}
115 delete[] p;
118 void f(int);
120 void testUseZeroAlloc3() {
121 int *p = new int[0];
122 f(*p); // newdelete-warning {{Use of memory allocated with size zero}}
123 delete[] p;
126 //---------------
127 // other checks
128 //---------------
130 class SomeClass {
131 public:
132 void f(int *p);
135 void f(int *p1, int *p2 = 0, int *p3 = 0);
136 void g(SomeClass &c, ...);
138 void testUseFirstArgAfterDelete() {
139 int *p = new int;
140 delete p;
141 f(p); // newdelete-warning{{Use of memory after it is freed}}
144 void testUseMiddleArgAfterDelete(int *p) {
145 delete p;
146 f(0, p); // newdelete-warning{{Use of memory after it is freed}}
149 void testUseLastArgAfterDelete(int *p) {
150 delete p;
151 f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}}
154 void testUseSeveralArgsAfterDelete(int *p) {
155 delete p;
156 f(p, p, p); // newdelete-warning{{Use of memory after it is freed}}
159 void testUseRefArgAfterDelete(SomeClass &c) {
160 delete &c;
161 g(c); // newdelete-warning{{Use of memory after it is freed}}
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}}
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}}
177 void testUseThisAfterDelete() {
178 SomeClass *c = new SomeClass;
179 delete c;
180 c->f(0); // newdelete-warning{{Use of memory after it is freed}}
183 void testDoubleDelete() {
184 int *p = new int;
185 delete p;
186 delete p; // newdelete-warning{{Attempt to free released memory}}
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'}}
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[]'}}
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[]'}}
205 //--------------------------------
206 // Test escape of newed const pointer. Note, a const pointer can be deleted.
207 //--------------------------------
208 struct StWithConstPtr {
209 const int *memp;
211 void escape(const int &x);
212 void escapeStruct(const StWithConstPtr &x);
213 void escapePtr(const StWithConstPtr *x);
214 void escapeVoidPtr(const void *x);
216 void testConstEscape() {
217 int *p = new int(1);
218 escape(*p);
219 } // no-warning
221 void testConstEscapeStruct() {
222 StWithConstPtr *St = new StWithConstPtr();
223 escapeStruct(*St);
224 } // no-warning
226 void testConstEscapeStructPtr() {
227 StWithConstPtr *St = new StWithConstPtr();
228 escapePtr(St);
229 } // no-warning
231 void testConstEscapeMember() {
232 StWithConstPtr St;
233 St.memp = new int(2);
234 escapeVoidPtr(St.memp);
235 } // no-warning
237 void testConstEscapePlacementNew() {
238 int *x = (int *)malloc(sizeof(int));
239 void *y = new (x) int;
240 escapeVoidPtr(y);
241 } // no-warning
243 //============== Test Uninitialized delete delete[]========================
244 void testUninitDelete() {
245 int *x;
246 int * y = new int;
247 delete y;
248 delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
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}}
258 void testUninitFree() {
259 int *x;
260 free(x); // expected-warning{{1st function call argument is an uninitialized value}}
263 void testUninitDeleteSink() {
264 int *x;
265 delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
266 (*(volatile int *)0 = 1); // no warn
269 void testUninitDeleteArraySink() {
270 int *x;
271 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
272 (*(volatile int *)0 = 1); // no warn
275 namespace reference_count {
276 class control_block {
277 unsigned count;
278 public:
279 control_block() : count(0) {}
280 void retain() { ++count; }
281 int release() { return --count; }
284 template <typename T>
285 class shared_ptr {
286 T *p;
287 control_block *control;
289 public:
290 shared_ptr() : p(0), control(0) {}
291 explicit shared_ptr(T *p) : p(p), control(new control_block) {
292 control->retain();
294 shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) {
295 if (control)
296 control->retain();
298 ~shared_ptr() {
299 if (control && control->release() == 0) {
300 delete p;
301 delete control;
305 T &operator *() {
306 return *p;
309 void swap(shared_ptr &other) {
310 T *tmp = p;
311 p = other.p;
312 other.p = tmp;
314 control_block *ctrlTmp = control;
315 control = other.control;
316 other.control = ctrlTmp;
320 template <typename T, typename... Args>
321 shared_ptr<T> make_shared(Args &&...args) {
322 return shared_ptr<T>(new T(static_cast<Args &&>(args)...));
325 void testSingle() {
326 shared_ptr<int> a(new int);
327 *a = 1;
330 void testMake() {
331 shared_ptr<int> a = make_shared<int>();
332 *a = 1;
335 void testMakeInParens() {
336 shared_ptr<int> a = (make_shared<int>()); // no warn
337 *a = 1;
340 void testDouble() {
341 shared_ptr<int> a(new int);
342 shared_ptr<int> b = a;
343 *a = 1;
346 void testInvalidated() {
347 shared_ptr<int> a(new int);
348 shared_ptr<int> b = a;
349 *a = 1;
351 extern void use(shared_ptr<int> &);
352 use(b);
355 void testNestedScope() {
356 shared_ptr<int> a(new int);
358 shared_ptr<int> b = a;
360 *a = 1;
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);
370 void testUseAfterFree() {
371 int *p = new int;
373 shared_ptr<int> a(p);
374 shared_ptr<int> b = a;
377 // FIXME: We should get a warning here, but we don't because we've
378 // conservatively modeled ~shared_ptr.
379 *p = 1;
383 // Test double delete
384 class DerefClass{
385 public:
386 int *x;
387 DerefClass() {}
388 ~DerefClass() {
389 int i = 0;
390 x = &i;
391 *x = 1;
395 void testDoubleDeleteClassInstance() {
396 DerefClass *foo = new DerefClass();
397 delete foo;
398 delete foo; // newdelete-warning {{Attempt to delete released memory}}
401 class EmptyClass{
402 public:
403 EmptyClass() {}
404 ~EmptyClass() {}
407 void testDoubleDeleteEmptyClass() {
408 EmptyClass *foo = new EmptyClass();
409 delete foo;
410 delete foo; // newdelete-warning {{Attempt to delete released memory}}
413 struct Base {
414 virtual ~Base() {}
417 struct Derived : Base {
420 Base *allocate() {
421 return new Derived;
424 void shouldNotReportLeak() {
425 Derived *p = (Derived *)allocate();
426 delete p;
429 template<void *allocate_fn(size_t)>
430 void* allocate_via_nttp(size_t n) {
431 return allocate_fn(n);
434 template<void deallocate_fn(void*)>
435 void deallocate_via_nttp(void* ptr) {
436 deallocate_fn(ptr);
439 void testNTTPNewNTTPDelete() {
440 void* p = allocate_via_nttp<::operator new>(10);
441 deallocate_via_nttp<::operator delete>(p);
442 } // no warn
444 void testNTTPNewDirectDelete() {
445 void* p = allocate_via_nttp<::operator new>(10);
446 ::operator delete(p);
447 } // no warn
449 void testDirectNewNTTPDelete() {
450 void* p = ::operator new(10);
451 deallocate_via_nttp<::operator delete>(p);
454 void not_free(void*) {
457 void testLeakBecauseNTTPIsNotDeallocation() {
458 void* p = ::operator new(10);
459 deallocate_via_nttp<not_free>(p);
460 } // leak-warning{{Potential leak of memory pointed to by 'p'}}