NewDelete-checker-test.cpp revision 651f13cea278ec967336033dd032faef0e9fc2ec
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); 7extern "C" void free (void* ptr); 8int *global; 9 10//------------------ 11// check for leaks 12//------------------ 13 14//----- Standard non-placement operators 15void testGlobalOpNew() { 16 void *p = operator new(0); 17} 18#ifdef LEAKS 19// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 20#endif 21 22void testGlobalOpNewArray() { 23 void *p = operator new[](0); 24} 25#ifdef LEAKS 26// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 27#endif 28 29void testGlobalNewExpr() { 30 int *p = new int; 31} 32#ifdef LEAKS 33// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 34#endif 35 36void testGlobalNewExprArray() { 37 int *p = new int[0]; 38} 39#ifdef LEAKS 40// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 41#endif 42 43//----- Standard nothrow placement operators 44void testGlobalNoThrowPlacementOpNewBeforeOverload() { 45 void *p = operator new(0, std::nothrow); 46} 47#ifdef LEAKS 48// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 49#endif 50 51void testGlobalNoThrowPlacementExprNewBeforeOverload() { 52 int *p = new(std::nothrow) int; 53} 54#ifdef LEAKS 55// expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 56#endif 57 58//----- Standard pointer placement operators 59void testGlobalPointerPlacementNew() { 60 int i; 61 62 void *p1 = operator new(0, &i); // no warn 63 64 void *p2 = operator new[](0, &i); // no warn 65 66 int *p3 = new(&i) int; // no warn 67 68 int *p4 = new(&i) int[0]; // no warn 69} 70 71//----- Other cases 72void testNewMemoryIsInHeap() { 73 int *p = new int; 74 if (global != p) // condition is always true as 'p' wraps a heap region that 75 // is different from a region wrapped by 'global' 76 global = p; // pointer escapes 77} 78 79struct PtrWrapper { 80 int *x; 81 82 PtrWrapper(int *input) : x(input) {} 83}; 84 85void testNewInvalidationPlacement(PtrWrapper *w) { 86 // Ensure that we don't consider this a leak. 87 new (w) PtrWrapper(new int); // no warn 88} 89 90//--------------- 91// other checks 92//--------------- 93 94class SomeClass { 95public: 96 void f(int *p); 97}; 98 99void f(int *p1, int *p2 = 0, int *p3 = 0); 100void g(SomeClass &c, ...); 101 102void testUseFirstArgAfterDelete() { 103 int *p = new int; 104 delete p; 105 f(p); // expected-warning{{Use of memory after it is freed}} 106} 107 108void testUseMiddleArgAfterDelete(int *p) { 109 delete p; 110 f(0, p); // expected-warning{{Use of memory after it is freed}} 111} 112 113void testUseLastArgAfterDelete(int *p) { 114 delete p; 115 f(0, 0, p); // expected-warning{{Use of memory after it is freed}} 116} 117 118void testUseSeveralArgsAfterDelete(int *p) { 119 delete p; 120 f(p, p, p); // expected-warning{{Use of memory after it is freed}} 121} 122 123void testUseRefArgAfterDelete(SomeClass &c) { 124 delete &c; 125 g(c); // expected-warning{{Use of memory after it is freed}} 126} 127 128void testVariadicArgAfterDelete() { 129 SomeClass c; 130 int *p = new int; 131 delete p; 132 g(c, 0, p); // expected-warning{{Use of memory after it is freed}} 133} 134 135void testUseMethodArgAfterDelete(int *p) { 136 SomeClass *c = new SomeClass; 137 delete p; 138 c->f(p); // expected-warning{{Use of memory after it is freed}} 139} 140 141void testUseThisAfterDelete() { 142 SomeClass *c = new SomeClass; 143 delete c; 144 c->f(0); // expected-warning{{Use of memory after it is freed}} 145} 146 147void testDeleteAlloca() { 148 int *p = (int *)__builtin_alloca(sizeof(int)); 149 delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}} 150} 151 152void testDoubleDelete() { 153 int *p = new int; 154 delete p; 155 delete p; // expected-warning{{Attempt to free released memory}} 156} 157 158void testExprDeleteArg() { 159 int i; 160 delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} 161} 162 163void testExprDeleteArrArg() { 164 int i; 165 delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} 166} 167 168void testAllocDeallocNames() { 169 int *p = new(std::nothrow) int[1]; 170 delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} 171} 172 173//-------------------------------- 174// Test escape of newed const pointer. Note, a const pointer can be deleted. 175//-------------------------------- 176struct StWithConstPtr { 177 const int *memp; 178}; 179void escape(const int &x); 180void escapeStruct(const StWithConstPtr &x); 181void escapePtr(const StWithConstPtr *x); 182void escapeVoidPtr(const void *x); 183 184void testConstEscape() { 185 int *p = new int(1); 186 escape(*p); 187} // no-warning 188 189void testConstEscapeStruct() { 190 StWithConstPtr *St = new StWithConstPtr(); 191 escapeStruct(*St); 192} // no-warning 193 194void testConstEscapeStructPtr() { 195 StWithConstPtr *St = new StWithConstPtr(); 196 escapePtr(St); 197} // no-warning 198 199void testConstEscapeMember() { 200 StWithConstPtr St; 201 St.memp = new int(2); 202 escapeVoidPtr(St.memp); 203} // no-warning 204 205void testConstEscapePlacementNew() { 206 int *x = (int *)malloc(sizeof(int)); 207 void *y = new (x) int; 208 escapeVoidPtr(y); 209} // no-warning 210 211//============== Test Uninitialized delete delete[]======================== 212void testUninitDelete() { 213 int *x; 214 int * y = new int; 215 delete y; 216 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 217} 218 219void testUninitDeleteArray() { 220 int *x; 221 int * y = new int[5]; 222 delete[] y; 223 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 224} 225 226void testUninitFree() { 227 int *x; 228 free(x); // expected-warning{{Function call argument is an uninitialized value}} 229} 230 231void testUninitDeleteSink() { 232 int *x; 233 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 234 (*(volatile int *)0 = 1); // no warn 235} 236 237void testUninitDeleteArraySink() { 238 int *x; 239 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 240 (*(volatile int *)0 = 1); // no warn 241} 242 243namespace reference_count { 244 class control_block { 245 unsigned count; 246 public: 247 control_block() : count(0) {} 248 void retain() { ++count; } 249 int release() { return --count; } 250 }; 251 252 template <typename T> 253 class shared_ptr { 254 T *p; 255 control_block *control; 256 257 public: 258 shared_ptr() : p(0), control(0) {} 259 explicit shared_ptr(T *p) : p(p), control(new control_block) { 260 control->retain(); 261 } 262 shared_ptr(shared_ptr &other) : p(other.p), control(other.control) { 263 if (control) 264 control->retain(); 265 } 266 ~shared_ptr() { 267 if (control && control->release() == 0) { 268 delete p; 269 delete control; 270 } 271 }; 272 273 T &operator *() { 274 return *p; 275 }; 276 277 void swap(shared_ptr &other) { 278 T *tmp = p; 279 p = other.p; 280 other.p = tmp; 281 282 control_block *ctrlTmp = control; 283 control = other.control; 284 other.control = ctrlTmp; 285 } 286 }; 287 288 void testSingle() { 289 shared_ptr<int> a(new int); 290 *a = 1; 291 } 292 293 void testDouble() { 294 shared_ptr<int> a(new int); 295 shared_ptr<int> b = a; 296 *a = 1; 297 } 298 299 void testInvalidated() { 300 shared_ptr<int> a(new int); 301 shared_ptr<int> b = a; 302 *a = 1; 303 304 extern void use(shared_ptr<int> &); 305 use(b); 306 } 307 308 void testNestedScope() { 309 shared_ptr<int> a(new int); 310 { 311 shared_ptr<int> b = a; 312 } 313 *a = 1; 314 } 315 316 void testSwap() { 317 shared_ptr<int> a(new int); 318 shared_ptr<int> b; 319 shared_ptr<int> c = a; 320 shared_ptr<int>(c).swap(b); 321 } 322 323 void testUseAfterFree() { 324 int *p = new int; 325 { 326 shared_ptr<int> a(p); 327 shared_ptr<int> b = a; 328 } 329 330 // FIXME: We should get a warning here, but we don't because we've 331 // conservatively modeled ~shared_ptr. 332 *p = 1; 333 } 334} 335 336// Test double delete 337class DerefClass{ 338public: 339 int *x; 340 DerefClass() {} 341 ~DerefClass() {*x = 1;} 342}; 343 344void testDoubleDeleteClassInstance() { 345 DerefClass *foo = new DerefClass(); 346 delete foo; 347 delete foo; // expected-warning {{Attempt to delete released memory}} 348} 349 350class EmptyClass{ 351public: 352 EmptyClass() {} 353 ~EmptyClass() {} 354}; 355 356void testDoubleDeleteEmptyClass() { 357 EmptyClass *foo = new EmptyClass(); 358 delete foo; 359 delete foo; // expected-warning {{Attempt to delete released memory}} 360} 361