[RISCV] Add shrinkwrap test cases showing gaps in current impl
[llvm-project.git] / clang / test / Analysis / NewDelete-checker-test.cpp
blob21b4cf817b5df6bbe4493e5f7169f172ed399f1e
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 //----- Standard non-placement operators
41 void testGlobalOpNew() {
42 void *p = operator new(0);
43 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
45 void testGlobalOpNewArray() {
46 void *p = operator new[](0);
47 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
49 void testGlobalNewExpr() {
50 int *p = new int;
51 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
53 void testGlobalNewExprArray() {
54 int *p = new int[0];
55 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
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'}}
62 void testGlobalNoThrowPlacementExprNewBeforeOverload() {
63 int *p = new(std::nothrow) int;
64 } // leak-warning{{Potential leak of memory pointed to by 'p'}}
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
74 struct PtrWrapper {
75 int *x;
77 PtrWrapper(int *input) : x(input) {}
80 void testNewInvalidationPlacement(PtrWrapper *w) {
81 // Ensure that we don't consider this a leak.
82 new (w) PtrWrapper(new int); // no warn
85 //-----------------------------------------
86 // check for usage of zero-allocated memory
87 //-----------------------------------------
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;
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;
101 void f(int);
103 void testUseZeroAlloc3() {
104 int *p = new int[0];
105 f(*p); // newdelete-warning {{Use of memory allocated with size zero}}
106 delete[] p;
109 //---------------
110 // other checks
111 //---------------
113 class SomeClass {
114 public:
115 void f(int *p);
118 void f(int *p1, int *p2 = 0, int *p3 = 0);
119 void g(SomeClass &c, ...);
121 void testUseFirstArgAfterDelete() {
122 int *p = new int;
123 delete p;
124 f(p); // newdelete-warning{{Use of memory after it is freed}}
127 void testUseMiddleArgAfterDelete(int *p) {
128 delete p;
129 f(0, p); // newdelete-warning{{Use of memory after it is freed}}
132 void testUseLastArgAfterDelete(int *p) {
133 delete p;
134 f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}}
137 void testUseSeveralArgsAfterDelete(int *p) {
138 delete p;
139 f(p, p, p); // newdelete-warning{{Use of memory after it is freed}}
142 void testUseRefArgAfterDelete(SomeClass &c) {
143 delete &c;
144 g(c); // newdelete-warning{{Use of memory after it is freed}}
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}}
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}}
160 void testUseThisAfterDelete() {
161 SomeClass *c = new SomeClass;
162 delete c;
163 c->f(0); // newdelete-warning{{Use of memory after it is freed}}
166 void testDoubleDelete() {
167 int *p = new int;
168 delete p;
169 delete p; // newdelete-warning{{Attempt to free released memory}}
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'}}
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[]'}}
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[]'}}
188 //--------------------------------
189 // Test escape of newed const pointer. Note, a const pointer can be deleted.
190 //--------------------------------
191 struct StWithConstPtr {
192 const int *memp;
194 void escape(const int &x);
195 void escapeStruct(const StWithConstPtr &x);
196 void escapePtr(const StWithConstPtr *x);
197 void escapeVoidPtr(const void *x);
199 void testConstEscape() {
200 int *p = new int(1);
201 escape(*p);
202 } // no-warning
204 void testConstEscapeStruct() {
205 StWithConstPtr *St = new StWithConstPtr();
206 escapeStruct(*St);
207 } // no-warning
209 void testConstEscapeStructPtr() {
210 StWithConstPtr *St = new StWithConstPtr();
211 escapePtr(St);
212 } // no-warning
214 void testConstEscapeMember() {
215 StWithConstPtr St;
216 St.memp = new int(2);
217 escapeVoidPtr(St.memp);
218 } // no-warning
220 void testConstEscapePlacementNew() {
221 int *x = (int *)malloc(sizeof(int));
222 void *y = new (x) int;
223 escapeVoidPtr(y);
224 } // no-warning
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}}
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}}
241 void testUninitFree() {
242 int *x;
243 free(x); // expected-warning{{1st function call argument is an uninitialized value}}
246 void testUninitDeleteSink() {
247 int *x;
248 delete x; // expected-warning{{Argument to 'delete' is uninitialized}}
249 (*(volatile int *)0 = 1); // no warn
252 void testUninitDeleteArraySink() {
253 int *x;
254 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}
255 (*(volatile int *)0 = 1); // no warn
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; }
267 template <typename T>
268 class shared_ptr {
269 T *p;
270 control_block *control;
272 public:
273 shared_ptr() : p(0), control(0) {}
274 explicit shared_ptr(T *p) : p(p), control(new control_block) {
275 control->retain();
277 shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) {
278 if (control)
279 control->retain();
281 ~shared_ptr() {
282 if (control && control->release() == 0) {
283 delete p;
284 delete control;
288 T &operator *() {
289 return *p;
292 void swap(shared_ptr &other) {
293 T *tmp = p;
294 p = other.p;
295 other.p = tmp;
297 control_block *ctrlTmp = control;
298 control = other.control;
299 other.control = ctrlTmp;
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)...));
308 void testSingle() {
309 shared_ptr<int> a(new int);
310 *a = 1;
313 void testMake() {
314 shared_ptr<int> a = make_shared<int>();
315 *a = 1;
318 void testMakeInParens() {
319 shared_ptr<int> a = (make_shared<int>()); // no warn
320 *a = 1;
323 void testDouble() {
324 shared_ptr<int> a(new int);
325 shared_ptr<int> b = a;
326 *a = 1;
329 void testInvalidated() {
330 shared_ptr<int> a(new int);
331 shared_ptr<int> b = a;
332 *a = 1;
334 extern void use(shared_ptr<int> &);
335 use(b);
338 void testNestedScope() {
339 shared_ptr<int> a(new int);
341 shared_ptr<int> b = a;
343 *a = 1;
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);
353 void testUseAfterFree() {
354 int *p = new int;
356 shared_ptr<int> a(p);
357 shared_ptr<int> b = a;
360 // FIXME: We should get a warning here, but we don't because we've
361 // conservatively modeled ~shared_ptr.
362 *p = 1;
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;
378 void testDoubleDeleteClassInstance() {
379 DerefClass *foo = new DerefClass();
380 delete foo;
381 delete foo; // newdelete-warning {{Attempt to delete released memory}}
384 class EmptyClass{
385 public:
386 EmptyClass() {}
387 ~EmptyClass() {}
390 void testDoubleDeleteEmptyClass() {
391 EmptyClass *foo = new EmptyClass();
392 delete foo;
393 delete foo; // newdelete-warning {{Attempt to delete released memory}}
396 struct Base {
397 virtual ~Base() {}
400 struct Derived : Base {
403 Base *allocate() {
404 return new Derived;
407 void shouldNotReportLeak() {
408 Derived *p = (Derived *)allocate();
409 delete p;
412 template<void *allocate_fn(size_t)>
413 void* allocate_via_nttp(size_t n) {
414 return allocate_fn(n);
417 template<void deallocate_fn(void*)>
418 void deallocate_via_nttp(void* ptr) {
419 deallocate_fn(ptr);
422 void testNTTPNewNTTPDelete() {
423 void* p = allocate_via_nttp<::operator new>(10);
424 deallocate_via_nttp<::operator delete>(p);
425 } // no warn
427 void testNTTPNewDirectDelete() {
428 void* p = allocate_via_nttp<::operator new>(10);
429 ::operator delete(p);
430 } // no warn
432 void testDirectNewNTTPDelete() {
433 void* p = ::operator new(10);
434 deallocate_via_nttp<::operator delete>(p);
437 void not_free(void*) {
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'}}