578 lines · cpp
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.NewDelete5//6// RUN: %clang_analyze_cc1 -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.NewDeleteLeaks11//12// RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \13// RUN: -verify=expected,leak \14// RUN: -analyzer-checker=core \15// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks16//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.NewDelete21//22// RUN: %clang_analyze_cc1 -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.NewDeleteLeaks27//28// RUN: %clang_analyze_cc1 -std=c++17 -fblocks %s \29// RUN: -verify=expected,leak,inspection \30// RUN: -analyzer-checker=core \31// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \32// RUN: -analyzer-checker=debug.ExprInspection33 34#include "Inputs/system-header-simulator-cxx.h"35 36typedef __typeof__(sizeof(int)) size_t;37extern "C" void *malloc(size_t);38extern "C" void free (void* ptr);39int *global;40 41//----- Standard non-placement operators42void testGlobalOpNew() {43 void *p = operator new(0);44} // leak-warning{{Potential leak of memory pointed to by 'p'}}45 46void testGlobalOpNewArray() {47 void *p = operator new[](0);48} // leak-warning{{Potential leak of memory pointed to by 'p'}}49 50void testGlobalNewExpr() {51 int *p = new int;52} // leak-warning{{Potential leak of memory pointed to by 'p'}}53 54void testGlobalNewExprArray() {55 int *p = new int[0];56} // leak-warning{{Potential leak of memory pointed to by 'p'}}57 58//----- Standard nothrow placement operators59void testGlobalNoThrowPlacementOpNewBeforeOverload() {60 void *p = operator new(0, std::nothrow);61} // leak-warning{{Potential leak of memory pointed to by 'p'}}62 63void testGlobalNoThrowPlacementExprNewBeforeOverload() {64 int *p = new(std::nothrow) int;65} // leak-warning{{Potential leak of memory pointed to by 'p'}}66 67//----- Standard pointer placement operators68void testGlobalPointerPlacementNew() {69 int i;70 void *p1 = operator new(0, &i); // no leak: placement new never allocates71 void *p2 = operator new[](0, &i); // no leak72 int *p3 = new(&i) int; // no leak73 int *p4 = new(&i) int[0]; // no leak74}75 76template<typename T>77void clang_analyzer_dump(T x);78 79void testPlacementNewBufValue() {80 int i = 10;81 int *p = new(&i) int;82 clang_analyzer_dump(p); // inspection-warning{{&i}}83 clang_analyzer_dump(*p); // inspection-warning{{10}}84}85 86void testPlacementNewBufValueExplicitOp() {87 int i = 10;88 int *p = (int*)operator new(sizeof(int), &i);89 clang_analyzer_dump(p); // inspection-warning{{&i}}90 clang_analyzer_dump(*p); // inspection-warning{{10}}91}92 93void testPlacementArrNewBufValueExplicitArrOp() {94 int i = 10;95 int *p = (int*)operator new[](sizeof(int), &i);96 clang_analyzer_dump(p); // inspection-warning{{&i}}97 clang_analyzer_dump(*p); // inspection-warning{{10}}98}99 100//----- Other cases101void testNewMemoryIsInHeap() {102 int *p = new int;103 if (global != p) // condition is always true as 'p' wraps a heap region that 104 // is different from a region wrapped by 'global'105 global = p; // pointer escapes106}107 108struct PtrWrapper {109 int *x;110 111 PtrWrapper(int *input) : x(input) {}112};113 114void testNewInvalidationPlacement(PtrWrapper *w) {115 // Ensure that we don't consider this a leak.116 new (w) PtrWrapper(new int); // no warn117}118 119//-----------------------------------------120// check for usage of zero-allocated memory121//-----------------------------------------122 123void testUseZeroAlloc1() {124 int *p = (int *)operator new(0);125 *p = 1; // newdelete-warning {{Use of memory allocated with size zero}}126 delete p;127}128 129int testUseZeroAlloc2() {130 int *p = (int *)operator new[](0);131 return p[0]; // newdelete-warning {{Use of memory allocated with size zero}}132 delete[] p;133}134 135void f(int);136 137void testUseZeroAlloc3() {138 int *p = new int[0];139 f(*p); // newdelete-warning {{Use of memory allocated with size zero}}140 delete[] p;141}142 143//---------------144// other checks145//---------------146 147class SomeClass {148public:149 void f(int *p);150};151 152void f(int *p1, int *p2 = 0, int *p3 = 0);153void g(SomeClass &c, ...);154 155void testUseFirstArgAfterDelete() {156 int *p = new int;157 delete p;158 f(p); // newdelete-warning{{Use of memory after it is released}}159}160 161void testUseMiddleArgAfterDelete(int *p) {162 delete p;163 f(0, p); // newdelete-warning{{Use of memory after it is released}}164}165 166void testUseLastArgAfterDelete(int *p) {167 delete p;168 f(0, 0, p); // newdelete-warning{{Use of memory after it is released}}169}170 171void testUseSeveralArgsAfterDelete(int *p) {172 delete p;173 f(p, p, p); // newdelete-warning{{Use of memory after it is released}}174}175 176void testUseRefArgAfterDelete(SomeClass &c) {177 delete &c;178 g(c); // newdelete-warning{{Use of memory after it is released}}179}180 181void testVariadicArgAfterDelete() {182 SomeClass c;183 int *p = new int;184 delete p;185 g(c, 0, p); // newdelete-warning{{Use of memory after it is released}}186}187 188void testUseMethodArgAfterDelete(int *p) {189 SomeClass *c = new SomeClass;190 delete p;191 c->f(p); // newdelete-warning{{Use of memory after it is released}}192}193 194void testUseThisAfterDelete() {195 SomeClass *c = new SomeClass;196 delete c;197 c->f(0); // newdelete-warning{{Use of memory after it is released}}198}199 200void testDoubleDelete() {201 int *p = new int;202 delete p;203 delete p; // newdelete-warning{{Attempt to release already released memory}}204}205 206void testExprDeleteArg() {207 int i;208 delete &i; // newdelete-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}209}210 211void testExprDeleteArrArg() {212 int i;213 delete[] & i; // newdelete-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}214}215 216void testAllocDeallocNames() {217 int *p = new(std::nothrow) int[1];218 delete[] (++p);219 // newdelete-warning@-1{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}220}221 222//--------------------------------223// Test escape of newed const pointer. Note, a const pointer can be deleted.224//--------------------------------225struct StWithConstPtr {226 const int *memp;227};228void escape(const int &x);229void escapeStruct(const StWithConstPtr &x);230void escapePtr(const StWithConstPtr *x);231void escapeVoidPtr(const void *x);232 233void testConstEscape() {234 int *p = new int(1);235 escape(*p);236} // no-warning237 238void testConstEscapeStruct() {239 StWithConstPtr *St = new StWithConstPtr();240 escapeStruct(*St);241} // no-warning242 243void testConstEscapeStructPtr() {244 StWithConstPtr *St = new StWithConstPtr();245 escapePtr(St);246} // no-warning247 248void testConstEscapeMember() {249 StWithConstPtr St;250 St.memp = new int(2);251 escapeVoidPtr(St.memp);252} // no-warning253 254void testConstEscapePlacementNew() {255 int *x = (int *)malloc(sizeof(int));256 void *y = new (x) int;257 escapeVoidPtr(y);258} // no-warning259 260//============== Test Uninitialized delete delete[]========================261void testUninitDelete() {262 int *x;263 int * y = new int;264 delete y;265 delete x; // expected-warning{{Argument to 'delete' is uninitialized}}266}267 268void testUninitDeleteArray() {269 int *x;270 int * y = new int[5];271 delete[] y;272 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}273}274 275void testUninitFree() {276 int *x;277 free(x); // expected-warning{{1st function call argument is an uninitialized value}}278}279 280void testUninitDeleteSink() {281 int *x;282 delete x; // expected-warning{{Argument to 'delete' is uninitialized}}283 (*(volatile int *)0 = 1); // no warn284}285 286void testUninitDeleteArraySink() {287 int *x;288 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}}289 (*(volatile int *)0 = 1); // no warn290}291 292namespace reference_count {293 class control_block {294 unsigned count;295 public:296 control_block() : count(0) {}297 void retain() { ++count; }298 int release() { return --count; }299 };300 301 template <typename T>302 class shared_ptr {303 T *p;304 control_block *control;305 306 public:307 shared_ptr() : p(0), control(0) {}308 explicit shared_ptr(T *p) : p(p), control(new control_block) {309 control->retain();310 }311 shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) {312 if (control)313 control->retain();314 }315 ~shared_ptr() {316 if (control && control->release() == 0) {317 delete p;318 delete control;319 }320 };321 322 T &operator *() {323 return *p;324 };325 326 void swap(shared_ptr &other) {327 T *tmp = p;328 p = other.p;329 other.p = tmp;330 331 control_block *ctrlTmp = control;332 control = other.control;333 other.control = ctrlTmp;334 }335 };336 337 template <typename T, typename... Args>338 shared_ptr<T> make_shared(Args &&...args) {339 return shared_ptr<T>(new T(static_cast<Args &&>(args)...));340 }341 342 void testSingle() {343 shared_ptr<int> a(new int);344 *a = 1;345 }346 347 void testMake() {348 shared_ptr<int> a = make_shared<int>();349 *a = 1;350 }351 352 void testMakeInParens() {353 shared_ptr<int> a = (make_shared<int>()); // no warn354 *a = 1;355 }356 357 void testDouble() {358 shared_ptr<int> a(new int);359 shared_ptr<int> b = a;360 *a = 1;361 }362 363 void testInvalidated() {364 shared_ptr<int> a(new int);365 shared_ptr<int> b = a;366 *a = 1;367 368 extern void use(shared_ptr<int> &);369 use(b);370 }371 372 void testNestedScope() {373 shared_ptr<int> a(new int);374 {375 shared_ptr<int> b = a;376 }377 *a = 1;378 }379 380 void testSwap() {381 shared_ptr<int> a(new int);382 shared_ptr<int> b;383 shared_ptr<int> c = a;384 shared_ptr<int>(c).swap(b);385 }386 387 void testUseAfterFree() {388 int *p = new int;389 {390 shared_ptr<int> a(p);391 shared_ptr<int> b = a;392 }393 394 // FIXME: We should get a warning here, but we don't because we've395 // conservatively modeled ~shared_ptr.396 *p = 1;397 }398}399 400// Test double delete401class DerefClass{402public:403 int *x;404 DerefClass() {}405 ~DerefClass() {406 int i = 0;407 x = &i;408 *x = 1;409 }410};411 412void testDoubleDeleteClassInstance() {413 DerefClass *foo = new DerefClass();414 delete foo;415 delete foo; // newdelete-warning {{Attempt to release already released memory}}416}417 418class EmptyClass{419public:420 EmptyClass() {}421 ~EmptyClass() {}422};423 424void testDoubleDeleteEmptyClass() {425 EmptyClass *foo = new EmptyClass();426 delete foo;427 delete foo; // newdelete-warning {{Attempt to release already released memory}}428}429 430struct Base {431 virtual ~Base() {}432};433 434struct Derived : Base {435};436 437Base *allocate() {438 return new Derived;439}440 441void shouldNotReportLeak() {442 Derived *p = (Derived *)allocate();443 delete p;444}445 446template<void *allocate_fn(size_t)>447void* allocate_via_nttp(size_t n) {448 return allocate_fn(n);449}450 451template<void deallocate_fn(void*)>452void deallocate_via_nttp(void* ptr) {453 deallocate_fn(ptr);454}455 456void testNTTPNewNTTPDelete() {457 void* p = allocate_via_nttp<::operator new>(10);458 deallocate_via_nttp<::operator delete>(p);459} // no warn460 461void testNTTPNewDirectDelete() {462 void* p = allocate_via_nttp<::operator new>(10);463 ::operator delete(p);464} // no warn465 466void testDirectNewNTTPDelete() {467 void* p = ::operator new(10);468 deallocate_via_nttp<::operator delete>(p);469}470 471void not_free(void*) {472}473 474void testLeakBecauseNTTPIsNotDeallocation() {475 void* p = ::operator new(10);476 deallocate_via_nttp<not_free>(p);477} // leak-warning{{Potential leak of memory pointed to by 'p'}}478 479namespace optional_union {480 template <typename T>481 class unique_ptr {482 T *q;483 public:484 unique_ptr() : q(new T) {}485 ~unique_ptr() {486 delete q;487 }488 };489 490 union custom_union_t {491 unique_ptr<int> present;492 char notpresent;493 custom_union_t() : present(unique_ptr<int>()) {}494 ~custom_union_t() {}495 };496 497 void testUnionCorrect() {498 custom_union_t a;499 a.present.~unique_ptr<int>();500 }501 502 void testUnionLeak() {503 custom_union_t a;504 } // leak-warning{{Potential leak of memory pointed to by 'a.present.q'}}505}506 507namespace gh153782 {508 509// Ensure we do not regress on the following use case.510 511namespace mutually_exclusive_test_case_1 {512struct StorageWrapper {513 // Imagine the destructor and copy constructor both call a reset() function (among other things).514 ~StorageWrapper() { delete parts; }515 StorageWrapper(StorageWrapper const&) = default;516 517 // Mind that there is no `parts = other.parts` assignment -- this is the bug we would like to find.518 void operator=(StorageWrapper&& other) { delete parts; } // newdelete-warning{{Attempt to release already released memory}}519 520 // Not provided, typically would do `parts = new long`.521 StorageWrapper();522 523 long* parts;524};525 526void test_non_trivial_struct_assignment() {527 StorageWrapper* object = new StorageWrapper[]{StorageWrapper()};528 object[0] = StorageWrapper(); // This assignment leads to the double-free.529}530} // mutually_exclusive_test_case_1531 532namespace mutually_exclusive_test_case_2 {533struct StorageWrapper {534 // Imagine the destructor and copy constructor both call a reset() function (among other things).535 ~StorageWrapper() { delete parts; }536 StorageWrapper(StorageWrapper const&) = default;537 538 // Mind that there is no `parts = other.parts` assignment -- this is the bug we would like to find.539 void operator=(StorageWrapper&& other) { delete parts; }540 541 // Not provided, typically would do `parts = new long`.542 StorageWrapper();543 544 long* parts;545};546 547void test_non_trivial_struct_assignment() {548 StorageWrapper* object = new StorageWrapper[]{StorageWrapper()};549 // object[0] = StorageWrapper(); // Remove the source of double free to make the potential leak appear.550} // leak-warning{{Potential leak of memory pointed to by 'object'}}551} // mutually_exclusive_test_case_2552 553namespace mutually_exclusive_test_case_3 {554struct StorageWrapper {555 // Imagine the destructor and copy constructor both call a reset() function (among other things).556 ~StorageWrapper() { delete parts; }557 StorageWrapper(StorageWrapper const&) = default;558 559 // Mind that there is no `parts = other.parts` assignment -- this is the bug we would like to find.560 void operator=(StorageWrapper&& other) { delete parts; } // newdelete-warning{{Attempt to release already released memory}}561 562 // Not provided, typically would do `parts = new long`.563 StorageWrapper();564 565 long* parts;566};567 568struct TestDoubleFreeWithInitializerList {569 StorageWrapper* Object;570 TestDoubleFreeWithInitializerList()571 : Object(new StorageWrapper[]{StorageWrapper()}) {572 Object[0] = StorageWrapper(); // This assignment leads to the double-free.573 }574};575} // mutually_exclusive_test_case_3576 577} // namespace gh153782578