1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s 2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s 3 #include "Inputs/system-header-simulator-cxx.h" 4 5 typedef __typeof__(sizeof(int)) size_t; 6 extern "C" void *malloc(size_t); 7 extern "C" void free (void* ptr); 8 int *global; 9 10 //------------------ 11 // check for leaks 12 //------------------ 13 14 //----- Standard non-placement operators 15 void 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 22 void 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 29 void 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 36 void 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 44 void 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 51 void 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 59 void 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 72 void 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 79 struct PtrWrapper { 80 int *x; 81 82 PtrWrapper(int *input) : x(input) {} 83 }; 84 85 void 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 // check for usage of zero-allocated memory 92 //----------------------------------------- 93 94 void testUseZeroAlloc1() { 95 int *p = (int *)operator new(0); 96 *p = 1; // expected-warning {{Use of zero-allocated memory}} 97 delete p; 98 } 99 100 int testUseZeroAlloc2() { 101 int *p = (int *)operator new[](0); 102 return p[0]; // expected-warning {{Use of zero-allocated memory}} 103 delete[] p; 104 } 105 106 void f(int); 107 108 void testUseZeroAlloc3() { 109 int *p = new int[0]; 110 f(*p); // expected-warning {{Use of zero-allocated memory}} 111 delete[] p; 112 } 113 114 //--------------- 115 // other checks 116 //--------------- 117 118 class SomeClass { 119 public: 120 void f(int *p); 121 }; 122 123 void f(int *p1, int *p2 = 0, int *p3 = 0); 124 void g(SomeClass &c, ...); 125 126 void testUseFirstArgAfterDelete() { 127 int *p = new int; 128 delete p; 129 f(p); // expected-warning{{Use of memory after it is freed}} 130 } 131 132 void testUseMiddleArgAfterDelete(int *p) { 133 delete p; 134 f(0, p); // expected-warning{{Use of memory after it is freed}} 135 } 136 137 void testUseLastArgAfterDelete(int *p) { 138 delete p; 139 f(0, 0, p); // expected-warning{{Use of memory after it is freed}} 140 } 141 142 void testUseSeveralArgsAfterDelete(int *p) { 143 delete p; 144 f(p, p, p); // expected-warning{{Use of memory after it is freed}} 145 } 146 147 void testUseRefArgAfterDelete(SomeClass &c) { 148 delete &c; 149 g(c); // expected-warning{{Use of memory after it is freed}} 150 } 151 152 void testVariadicArgAfterDelete() { 153 SomeClass c; 154 int *p = new int; 155 delete p; 156 g(c, 0, p); // expected-warning{{Use of memory after it is freed}} 157 } 158 159 void testUseMethodArgAfterDelete(int *p) { 160 SomeClass *c = new SomeClass; 161 delete p; 162 c->f(p); // expected-warning{{Use of memory after it is freed}} 163 } 164 165 void testUseThisAfterDelete() { 166 SomeClass *c = new SomeClass; 167 delete c; 168 c->f(0); // expected-warning{{Use of memory after it is freed}} 169 } 170 171 void testDoubleDelete() { 172 int *p = new int; 173 delete p; 174 delete p; // expected-warning{{Attempt to free released memory}} 175 } 176 177 void testExprDeleteArg() { 178 int i; 179 delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} 180 } 181 182 void testExprDeleteArrArg() { 183 int i; 184 delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} 185 } 186 187 void testAllocDeallocNames() { 188 int *p = new(std::nothrow) int[1]; 189 delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} 190 } 191 192 //-------------------------------- 193 // Test escape of newed const pointer. Note, a const pointer can be deleted. 194 //-------------------------------- 195 struct StWithConstPtr { 196 const int *memp; 197 }; 198 void escape(const int &x); 199 void escapeStruct(const StWithConstPtr &x); 200 void escapePtr(const StWithConstPtr *x); 201 void escapeVoidPtr(const void *x); 202 203 void testConstEscape() { 204 int *p = new int(1); 205 escape(*p); 206 } // no-warning 207 208 void testConstEscapeStruct() { 209 StWithConstPtr *St = new StWithConstPtr(); 210 escapeStruct(*St); 211 } // no-warning 212 213 void testConstEscapeStructPtr() { 214 StWithConstPtr *St = new StWithConstPtr(); 215 escapePtr(St); 216 } // no-warning 217 218 void testConstEscapeMember() { 219 StWithConstPtr St; 220 St.memp = new int(2); 221 escapeVoidPtr(St.memp); 222 } // no-warning 223 224 void testConstEscapePlacementNew() { 225 int *x = (int *)malloc(sizeof(int)); 226 void *y = new (x) int; 227 escapeVoidPtr(y); 228 } // no-warning 229 230 //============== Test Uninitialized delete delete[]======================== 231 void testUninitDelete() { 232 int *x; 233 int * y = new int; 234 delete y; 235 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 236 } 237 238 void testUninitDeleteArray() { 239 int *x; 240 int * y = new int[5]; 241 delete[] y; 242 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 243 } 244 245 void testUninitFree() { 246 int *x; 247 free(x); // expected-warning{{Function call argument is an uninitialized value}} 248 } 249 250 void testUninitDeleteSink() { 251 int *x; 252 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 253 (*(volatile int *)0 = 1); // no warn 254 } 255 256 void testUninitDeleteArraySink() { 257 int *x; 258 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 259 (*(volatile int *)0 = 1); // no warn 260 } 261 262 namespace reference_count { 263 class control_block { 264 unsigned count; 265 public: 266 control_block() : count(0) {} 267 void retain() { ++count; } 268 int release() { return --count; } 269 }; 270 271 template <typename T> 272 class shared_ptr { 273 T *p; 274 control_block *control; 275 276 public: 277 shared_ptr() : p(0), control(0) {} 278 explicit shared_ptr(T *p) : p(p), control(new control_block) { 279 control->retain(); 280 } 281 shared_ptr(shared_ptr &other) : p(other.p), control(other.control) { 282 if (control) 283 control->retain(); 284 } 285 ~shared_ptr() { 286 if (control && control->release() == 0) { 287 delete p; 288 delete control; 289 } 290 }; 291 292 T &operator *() { 293 return *p; 294 }; 295 296 void swap(shared_ptr &other) { 297 T *tmp = p; 298 p = other.p; 299 other.p = tmp; 300 301 control_block *ctrlTmp = control; 302 control = other.control; 303 other.control = ctrlTmp; 304 } 305 }; 306 307 void testSingle() { 308 shared_ptr<int> a(new int); 309 *a = 1; 310 } 311 312 void testDouble() { 313 shared_ptr<int> a(new int); 314 shared_ptr<int> b = a; 315 *a = 1; 316 } 317 318 void testInvalidated() { 319 shared_ptr<int> a(new int); 320 shared_ptr<int> b = a; 321 *a = 1; 322 323 extern void use(shared_ptr<int> &); 324 use(b); 325 } 326 327 void testNestedScope() { 328 shared_ptr<int> a(new int); 329 { 330 shared_ptr<int> b = a; 331 } 332 *a = 1; 333 } 334 335 void testSwap() { 336 shared_ptr<int> a(new int); 337 shared_ptr<int> b; 338 shared_ptr<int> c = a; 339 shared_ptr<int>(c).swap(b); 340 } 341 342 void testUseAfterFree() { 343 int *p = new int; 344 { 345 shared_ptr<int> a(p); 346 shared_ptr<int> b = a; 347 } 348 349 // FIXME: We should get a warning here, but we don't because we've 350 // conservatively modeled ~shared_ptr. 351 *p = 1; 352 } 353 } 354 355 // Test double delete 356 class DerefClass{ 357 public: 358 int *x; 359 DerefClass() {} 360 ~DerefClass() {*x = 1;} 361 }; 362 363 void testDoubleDeleteClassInstance() { 364 DerefClass *foo = new DerefClass(); 365 delete foo; 366 delete foo; // expected-warning {{Attempt to delete released memory}} 367 } 368 369 class EmptyClass{ 370 public: 371 EmptyClass() {} 372 ~EmptyClass() {} 373 }; 374 375 void testDoubleDeleteEmptyClass() { 376 EmptyClass *foo = new EmptyClass(); 377 delete foo; 378 delete foo; // expected-warning {{Attempt to delete released memory}} 379 } 380