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 11 // 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 16 // 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 21 // 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 27 // 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 32 33 #include "Inputs/system-header-simulator-cxx.h" 34 35 typedef __typeof__(sizeof(int)) size_t; 36 extern "C" void *malloc(size_t); 37 extern "C" void free (void* ptr); 38 int *global; 39 40 //------------------ 41 // check for leaks 42 //------------------ 43 44 //----- Standard non-placement operators 45 void testGlobalOpNew() { 46 void *p = operator new(0); 47 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 48 49 void testGlobalOpNewArray() { 50 void *p = operator new[](0); 51 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 52 53 void testGlobalNewExpr() { 54 int *p = new int; 55 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 56 57 void testGlobalNewExprArray() { 58 int *p = new int[0]; 59 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 60 61 //----- Standard nothrow placement operators 62 void testGlobalNoThrowPlacementOpNewBeforeOverload() { 63 void *p = operator new(0, std::nothrow); 64 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 65 66 void testGlobalNoThrowPlacementExprNewBeforeOverload() { 67 int *p = new(std::nothrow) int; 68 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 69 70 //----- Standard pointer placement operators 71 void testGlobalPointerPlacementNew() { 72 int i; 73 74 void *p1 = operator new(0, &i); // no warn 75 76 void *p2 = operator new[](0, &i); // no warn 77 78 int *p3 = new(&i) int; // no warn 79 80 int *p4 = new(&i) int[0]; // no warn 81 } 82 83 //----- Other cases 84 void testNewMemoryIsInHeap() { 85 int *p = new int; 86 if (global != p) // condition is always true as 'p' wraps a heap region that 87 // is different from a region wrapped by 'global' 88 global = p; // pointer escapes 89 } 90 91 struct PtrWrapper { 92 int *x; 93 94 PtrWrapper(int *input) : x(input) {} 95 }; 96 97 void testNewInvalidationPlacement(PtrWrapper *w) { 98 // Ensure that we don't consider this a leak. 99 new (w) PtrWrapper(new int); // no warn 100 } 101 102 //----------------------------------------- 103 // check for usage of zero-allocated memory 104 //----------------------------------------- 105 106 void testUseZeroAlloc1() { 107 int *p = (int *)operator new(0); 108 *p = 1; // newdelete-warning {{Use of memory allocated with size zero}} 109 delete p; 110 } 111 112 int testUseZeroAlloc2() { 113 int *p = (int *)operator new[](0); 114 return p[0]; // newdelete-warning {{Use of memory allocated with size zero}} 115 delete[] p; 116 } 117 118 void f(int); 119 120 void testUseZeroAlloc3() { 121 int *p = new int[0]; 122 f(*p); // newdelete-warning {{Use of memory allocated with size zero}} 123 delete[] p; 124 } 125 126 //--------------- 127 // other checks 128 //--------------- 129 130 class SomeClass { 131 public: 132 void f(int *p); 133 }; 134 135 void f(int *p1, int *p2 = 0, int *p3 = 0); 136 void g(SomeClass &c, ...); 137 138 void testUseFirstArgAfterDelete() { 139 int *p = new int; 140 delete p; 141 f(p); // newdelete-warning{{Use of memory after it is freed}} 142 } 143 144 void testUseMiddleArgAfterDelete(int *p) { 145 delete p; 146 f(0, p); // newdelete-warning{{Use of memory after it is freed}} 147 } 148 149 void testUseLastArgAfterDelete(int *p) { 150 delete p; 151 f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}} 152 } 153 154 void testUseSeveralArgsAfterDelete(int *p) { 155 delete p; 156 f(p, p, p); // newdelete-warning{{Use of memory after it is freed}} 157 } 158 159 void testUseRefArgAfterDelete(SomeClass &c) { 160 delete &c; 161 g(c); // newdelete-warning{{Use of memory after it is freed}} 162 } 163 164 void testVariadicArgAfterDelete() { 165 SomeClass c; 166 int *p = new int; 167 delete p; 168 g(c, 0, p); // newdelete-warning{{Use of memory after it is freed}} 169 } 170 171 void testUseMethodArgAfterDelete(int *p) { 172 SomeClass *c = new SomeClass; 173 delete p; 174 c->f(p); // newdelete-warning{{Use of memory after it is freed}} 175 } 176 177 void testUseThisAfterDelete() { 178 SomeClass *c = new SomeClass; 179 delete c; 180 c->f(0); // newdelete-warning{{Use of memory after it is freed}} 181 } 182 183 void testDoubleDelete() { 184 int *p = new int; 185 delete p; 186 delete p; // newdelete-warning{{Attempt to free released memory}} 187 } 188 189 void testExprDeleteArg() { 190 int i; 191 delete &i; // newdelete-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} 192 } 193 194 void testExprDeleteArrArg() { 195 int i; 196 delete[] & i; // newdelete-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} 197 } 198 199 void testAllocDeallocNames() { 200 int *p = new(std::nothrow) int[1]; 201 delete[] (++p); 202 // newdelete-warning@-1{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} 203 } 204 205 //-------------------------------- 206 // Test escape of newed const pointer. Note, a const pointer can be deleted. 207 //-------------------------------- 208 struct StWithConstPtr { 209 const int *memp; 210 }; 211 void escape(const int &x); 212 void escapeStruct(const StWithConstPtr &x); 213 void escapePtr(const StWithConstPtr *x); 214 void escapeVoidPtr(const void *x); 215 216 void testConstEscape() { 217 int *p = new int(1); 218 escape(*p); 219 } // no-warning 220 221 void testConstEscapeStruct() { 222 StWithConstPtr *St = new StWithConstPtr(); 223 escapeStruct(*St); 224 } // no-warning 225 226 void testConstEscapeStructPtr() { 227 StWithConstPtr *St = new StWithConstPtr(); 228 escapePtr(St); 229 } // no-warning 230 231 void testConstEscapeMember() { 232 StWithConstPtr St; 233 St.memp = new int(2); 234 escapeVoidPtr(St.memp); 235 } // no-warning 236 237 void testConstEscapePlacementNew() { 238 int *x = (int *)malloc(sizeof(int)); 239 void *y = new (x) int; 240 escapeVoidPtr(y); 241 } // no-warning 242 243 //============== Test Uninitialized delete delete[]======================== 244 void testUninitDelete() { 245 int *x; 246 int * y = new int; 247 delete y; 248 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 249 } 250 251 void testUninitDeleteArray() { 252 int *x; 253 int * y = new int[5]; 254 delete[] y; 255 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 256 } 257 258 void testUninitFree() { 259 int *x; 260 free(x); // expected-warning{{1st function call argument is an uninitialized value}} 261 } 262 263 void testUninitDeleteSink() { 264 int *x; 265 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 266 (*(volatile int *)0 = 1); // no warn 267 } 268 269 void testUninitDeleteArraySink() { 270 int *x; 271 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 272 (*(volatile int *)0 = 1); // no warn 273 } 274 275 namespace reference_count { 276 class control_block { 277 unsigned count; 278 public: 279 control_block() : count(0) {} 280 void retain() { ++count; } 281 int release() { return --count; } 282 }; 283 284 template <typename T> 285 class shared_ptr { 286 T *p; 287 control_block *control; 288 289 public: 290 shared_ptr() : p(0), control(0) {} 291 explicit shared_ptr(T *p) : p(p), control(new control_block) { 292 control->retain(); 293 } 294 shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) { 295 if (control) 296 control->retain(); 297 } 298 ~shared_ptr() { 299 if (control && control->release() == 0) { 300 delete p; 301 delete control; 302 } 303 }; 304 305 T &operator *() { 306 return *p; 307 }; 308 309 void swap(shared_ptr &other) { 310 T *tmp = p; 311 p = other.p; 312 other.p = tmp; 313 314 control_block *ctrlTmp = control; 315 control = other.control; 316 other.control = ctrlTmp; 317 } 318 }; 319 320 template <typename T, typename... Args> 321 shared_ptr<T> make_shared(Args &&...args) { 322 return shared_ptr<T>(new T(static_cast<Args &&>(args)...)); 323 } 324 325 void testSingle() { 326 shared_ptr<int> a(new int); 327 *a = 1; 328 } 329 330 void testMake() { 331 shared_ptr<int> a = make_shared<int>(); 332 *a = 1; 333 } 334 335 void testMakeInParens() { 336 shared_ptr<int> a = (make_shared<int>()); // no warn 337 *a = 1; 338 } 339 340 void testDouble() { 341 shared_ptr<int> a(new int); 342 shared_ptr<int> b = a; 343 *a = 1; 344 } 345 346 void testInvalidated() { 347 shared_ptr<int> a(new int); 348 shared_ptr<int> b = a; 349 *a = 1; 350 351 extern void use(shared_ptr<int> &); 352 use(b); 353 } 354 355 void testNestedScope() { 356 shared_ptr<int> a(new int); 357 { 358 shared_ptr<int> b = a; 359 } 360 *a = 1; 361 } 362 363 void testSwap() { 364 shared_ptr<int> a(new int); 365 shared_ptr<int> b; 366 shared_ptr<int> c = a; 367 shared_ptr<int>(c).swap(b); 368 } 369 370 void testUseAfterFree() { 371 int *p = new int; 372 { 373 shared_ptr<int> a(p); 374 shared_ptr<int> b = a; 375 } 376 377 // FIXME: We should get a warning here, but we don't because we've 378 // conservatively modeled ~shared_ptr. 379 *p = 1; 380 } 381 } 382 383 // Test double delete 384 class DerefClass{ 385 public: 386 int *x; 387 DerefClass() {} 388 ~DerefClass() {*x = 1;} 389 }; 390 391 void testDoubleDeleteClassInstance() { 392 DerefClass *foo = new DerefClass(); 393 delete foo; 394 delete foo; // newdelete-warning {{Attempt to delete released memory}} 395 } 396 397 class EmptyClass{ 398 public: 399 EmptyClass() {} 400 ~EmptyClass() {} 401 }; 402 403 void testDoubleDeleteEmptyClass() { 404 EmptyClass *foo = new EmptyClass(); 405 delete foo; 406 delete foo; // newdelete-warning {{Attempt to delete released memory}} 407 } 408 409 struct Base { 410 virtual ~Base() {} 411 }; 412 413 struct Derived : Base { 414 }; 415 416 Base *allocate() { 417 return new Derived; 418 } 419 420 void shouldNotReportLeak() { 421 Derived *p = (Derived *)allocate(); 422 delete p; 423 } 424 425 template<void *allocate_fn(size_t)> 426 void* allocate_via_nttp(size_t n) { 427 return allocate_fn(n); 428 } 429 430 template<void deallocate_fn(void*)> 431 void deallocate_via_nttp(void* ptr) { 432 deallocate_fn(ptr); 433 } 434 435 void testNTTPNewNTTPDelete() { 436 void* p = allocate_via_nttp<::operator new>(10); 437 deallocate_via_nttp<::operator delete>(p); 438 } // no warn 439 440 void testNTTPNewDirectDelete() { 441 void* p = allocate_via_nttp<::operator new>(10); 442 ::operator delete(p); 443 } // no warn 444 445 void testDirectNewNTTPDelete() { 446 void* p = ::operator new(10); 447 deallocate_via_nttp<::operator delete>(p); 448 } 449 450 void not_free(void*) { 451 } 452 453 void testLeakBecauseNTTPIsNotDeallocation() { 454 void* p = ::operator new(10); 455 deallocate_via_nttp<not_free>(p); 456 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 457