brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.5 KiB · fd831cc Raw
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