NewDelete-checker-test.cpp revision 50fa64d4411a42e0b4f373a84d8d4f5cbf339ea3
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
210
211namespace reference_count {
212  class control_block {
213    unsigned count;
214  public:
215    control_block() : count(0) {}
216    void retain() { ++count; }
217    int release() { return --count; }
218  };
219
220  template <typename T>
221  class shared_ptr {
222    T *p;
223    control_block *control;
224
225  public:
226    shared_ptr() : p(0), control(0) {}
227    explicit shared_ptr(T *p) : p(p), control(new control_block) {
228      control->retain();
229    }
230    shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
231      if (control)
232          control->retain();
233    }
234    ~shared_ptr() {
235      if (control && control->release() == 0) {
236        delete p;
237        delete control;
238      }
239    };
240
241    T &operator *() {
242      return *p;
243    };
244
245    void swap(shared_ptr &other) {
246      T *tmp = p;
247      p = other.p;
248      other.p = tmp;
249
250      control_block *ctrlTmp = control;
251      control = other.control;
252      other.control = ctrlTmp;
253    }
254  };
255
256  void testSingle() {
257    shared_ptr<int> a(new int);
258    *a = 1;
259  }
260
261  void testDouble() {
262    shared_ptr<int> a(new int);
263    shared_ptr<int> b = a;
264    *a = 1;
265  }
266
267  void testInvalidated() {
268    shared_ptr<int> a(new int);
269    shared_ptr<int> b = a;
270    *a = 1;
271
272    extern void use(shared_ptr<int> &);
273    use(b);
274  }
275
276  void testNestedScope() {
277    shared_ptr<int> a(new int);
278    {
279      shared_ptr<int> b = a;
280    }
281    *a = 1;
282  }
283
284  void testSwap() {
285    shared_ptr<int> a(new int);
286    shared_ptr<int> b;
287    shared_ptr<int> c = a;
288    shared_ptr<int>(c).swap(b);
289  }
290
291  void testUseAfterFree() {
292    int *p = new int;
293    {
294      shared_ptr<int> a(p);
295      shared_ptr<int> b = a;
296    }
297
298    // FIXME: We should get a warning here, but we don't because we've
299    // conservatively modeled ~shared_ptr.
300    *p = 1;
301  }
302}
303
304