NewDelete-checker-test.cpp revision 9df151c5bc2a746096632bbd21dc61e18675ed55
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
2// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
3#include "Inputs/system-header-simulator-cxx.h"
4
5typedef __typeof__(sizeof(int)) size_t;
6extern "C" void *malloc(size_t);
7int *global;
8
9//------------------
10// check for leaks
11//------------------
12
13//----- Standard non-placement operators
14void testGlobalOpNew() {
15  void *p = operator new(0);
16}
17#ifdef LEAKS
18// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
19#endif
20
21void testGlobalOpNewArray() {
22  void *p = operator new[](0);
23}
24#ifdef LEAKS
25// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
26#endif
27
28void testGlobalNewExpr() {
29  int *p = new int;
30}
31#ifdef LEAKS
32// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
33#endif
34
35void testGlobalNewExprArray() {
36  int *p = new int[0];
37}
38#ifdef LEAKS
39// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
40#endif
41
42//----- Standard nothrow placement operators
43void testGlobalNoThrowPlacementOpNewBeforeOverload() {
44  void *p = operator new(0, std::nothrow);
45}
46#ifdef LEAKS
47// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
48#endif
49
50void testGlobalNoThrowPlacementExprNewBeforeOverload() {
51  int *p = new(std::nothrow) int;
52}
53#ifdef LEAKS
54// expected-warning@-2{{Potential leak of memory pointed to by 'p'}}
55#endif
56
57//----- Standard pointer placement operators
58void testGlobalPointerPlacementNew() {
59  int i;
60
61  void *p1 = operator new(0, &i); // no warn
62
63  void *p2 = operator new[](0, &i); // no warn
64
65  int *p3 = new(&i) int; // no warn
66
67  int *p4 = new(&i) int[0]; // no warn
68}
69
70//----- Other cases
71void testNewMemoryIsInHeap() {
72  int *p = new int;
73  if (global != p) // condition is always true as 'p' wraps a heap region that
74                   // is different from a region wrapped by 'global'
75    global = p; // pointer escapes
76}
77
78struct PtrWrapper {
79  int *x;
80
81  PtrWrapper(int *input) : x(input) {}
82};
83
84void testNewInvalidationPlacement(PtrWrapper *w) {
85  // Ensure that we don't consider this a leak.
86  new (w) PtrWrapper(new int); // no warn
87}
88
89//---------------
90// other checks
91//---------------
92
93class SomeClass {
94public:
95  void f(int *p);
96};
97
98void f(int *p1, int *p2 = 0, int *p3 = 0);
99void g(SomeClass &c, ...);
100
101void testUseFirstArgAfterDelete() {
102  int *p = new int;
103  delete p;
104  f(p); // expected-warning{{Use of memory after it is freed}}
105}
106
107void testUseMiddleArgAfterDelete(int *p) {
108  delete p;
109  f(0, p); // expected-warning{{Use of memory after it is freed}}
110}
111
112void testUseLastArgAfterDelete(int *p) {
113  delete p;
114  f(0, 0, p); // expected-warning{{Use of memory after it is freed}}
115}
116
117void testUseSeveralArgsAfterDelete(int *p) {
118  delete p;
119  f(p, p, p); // expected-warning{{Use of memory after it is freed}}
120}
121
122void testUseRefArgAfterDelete(SomeClass &c) {
123  delete &c;
124  g(c); // expected-warning{{Use of memory after it is freed}}
125}
126
127void testVariadicArgAfterDelete() {
128  SomeClass c;
129  int *p = new int;
130  delete p;
131  g(c, 0, p); // expected-warning{{Use of memory after it is freed}}
132}
133
134void testUseMethodArgAfterDelete(int *p) {
135  SomeClass *c = new SomeClass;
136  delete p;
137  c->f(p); // expected-warning{{Use of memory after it is freed}}
138}
139
140void testUseThisAfterDelete() {
141  SomeClass *c = new SomeClass;
142  delete c;
143  c->f(0); // expected-warning{{Use of memory after it is freed}}
144}
145
146void testDeleteAlloca() {
147  int *p = (int *)__builtin_alloca(sizeof(int));
148  delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
149}
150
151void testDoubleDelete() {
152  int *p = new int;
153  delete p;
154  delete p; // expected-warning{{Attempt to free released memory}}
155}
156
157void testExprDeleteArg() {
158  int i;
159  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
160}
161
162void testExprDeleteArrArg() {
163  int i;
164  delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
165}
166
167void testAllocDeallocNames() {
168  int *p = new(std::nothrow) int[1];
169  delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
170}
171
172//--------------------------------
173// Test escape of newed const pointer. Note, a const pointer can be deleted.
174//--------------------------------
175struct StWithConstPtr {
176  const int *memp;
177};
178void escape(const int &x);
179void escapeStruct(const StWithConstPtr &x);
180void escapePtr(const StWithConstPtr *x);
181void escapeVoidPtr(const void *x);
182
183void testConstEscape() {
184  int *p = new int(1);
185  escape(*p);
186} // no-warning
187
188void testConstEscapeStruct() {
189  StWithConstPtr *St = new StWithConstPtr();
190  escapeStruct(*St);
191} // no-warning
192
193void testConstEscapeStructPtr() {
194  StWithConstPtr *St = new StWithConstPtr();
195  escapePtr(St);
196} // no-warning
197
198void testConstEscapeMember() {
199  StWithConstPtr St;
200  St.memp = new int(2);
201  escapeVoidPtr(St.memp);
202} // no-warning
203
204void testConstEscapePlacementNew() {
205  int *x = (int *)malloc(sizeof(int));
206  void *y = new (x) int;
207  escapeVoidPtr(y);
208} // no-warning
209