brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.2 KiB · 9e00e93 Raw
598 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-disable-checker=core.FixedAddressDereference -analyzer-config c++-inlining=destructors -Wno-null-dereference -Wno-inaccessible-base -verify -analyzer-config eagerly-assume=false %s2 3void clang_analyzer_eval(bool);4void clang_analyzer_checkInlined(bool);5 6class A {7public:8  ~A() { 9    int *x = 0;10    *x = 3; // expected-warning{{Dereference of null pointer}}11  }12};13 14int main() {15  A a;16}17 18 19typedef __typeof(sizeof(int)) size_t;20void *malloc(size_t);21void free(void *);22 23class SmartPointer {24  void *X;25public:26  SmartPointer(void *x) : X(x) {}27  ~SmartPointer() {28    free(X);29  }30};31 32void testSmartPointer() {33  char *mem = (char*)malloc(4);34  {35    SmartPointer Deleter(mem);36    // destructor called here37  }38  *mem = 0; // expected-warning{{Use of memory after it is released}}39}40 41 42void doSomething();43void testSmartPointer2() {44  char *mem = (char*)malloc(4);45  {46    SmartPointer Deleter(mem);47    // Remove dead bindings...48    doSomething();49    // destructor called here50  }51  *mem = 0; // expected-warning{{Use of memory after it is released}}52}53 54 55class Subclass : public SmartPointer {56public:57  Subclass(void *x) : SmartPointer(x) {}58};59 60void testSubclassSmartPointer() {61  char *mem = (char*)malloc(4);62  {63    Subclass Deleter(mem);64    // Remove dead bindings...65    doSomething();66    // destructor called here67  }68  *mem = 0; // expected-warning{{Use of memory after it is released}}69}70 71 72class MultipleInheritance : public Subclass, public SmartPointer {73public:74  MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}75};76 77void testMultipleInheritance1() {78  char *mem = (char*)malloc(4);79  {80    MultipleInheritance Deleter(mem, 0);81    // Remove dead bindings...82    doSomething();83    // destructor called here84  }85  *mem = 0; // expected-warning{{Use of memory after it is released}}86}87 88void testMultipleInheritance2() {89  char *mem = (char*)malloc(4);90  {91    MultipleInheritance Deleter(0, mem);92    // Remove dead bindings...93    doSomething();94    // destructor called here95  }96  *mem = 0; // expected-warning{{Use of memory after it is released}}97}98 99void testMultipleInheritance3() {100  char *mem = (char*)malloc(4);101  {102    MultipleInheritance Deleter(mem, mem);103    // Remove dead bindings...104    doSomething();105    // destructor called here106    // expected-warning@28 {{Attempt to release already released memory}}107  }108}109 110 111class SmartPointerMember {112  SmartPointer P;113public:114  SmartPointerMember(void *x) : P(x) {}115};116 117void testSmartPointerMember() {118  char *mem = (char*)malloc(4);119  {120    SmartPointerMember Deleter(mem);121    // Remove dead bindings...122    doSomething();123    // destructor called here124  }125  *mem = 0; // expected-warning{{Use of memory after it is release}}126}127 128 129struct IntWrapper {130  IntWrapper() : x(0) {}131  ~IntWrapper();132  int *x;133};134 135void testArrayInvalidation() {136  int i = 42;137  int j = 42;138 139  {140    IntWrapper arr[2];141 142    // There should be no undefined value warnings here.143    clang_analyzer_eval(arr[0].x == 0); // expected-warning{{TRUE}}144    clang_analyzer_eval(arr[1].x == 0); // expected-warning{{TRUE}}145 146    arr[0].x = &i;147    arr[1].x = &j;148    clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}149    clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}150  }151 152  // The destructors should have invalidated i and j.153  clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}154  clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}155}156 157 158 159// Don't crash on a default argument inside an initializer.160struct DefaultArg {161  DefaultArg(int x = 0) {}162  ~DefaultArg();163};164 165struct InheritsDefaultArg : DefaultArg {166  InheritsDefaultArg() {}167  virtual ~InheritsDefaultArg();168};169 170void testDefaultArg() {171  InheritsDefaultArg a;172  // Force a bug to be emitted.173  *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}174}175 176 177namespace DestructorVirtualCalls {178  class A {179  public:180    int *out1, *out2, *out3;181 182    virtual int get() { return 1; }183 184    ~A() {185      *out1 = get();186    }187  };188 189  class B : public A {190  public:191    virtual int get() { return 2; }192 193    ~B() {194      *out2 = get();195    }196  };197 198  class C : public B {199  public:200    virtual int get() { return 3; }201 202    ~C() {203      *out3 = get();204    }205  };206 207  void test() {208    int a, b, c;209 210    // New scope for the C object.211    {212      C obj;213      clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}214 215      // Correctness check for devirtualization.216      A *base = &obj;217      clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}218 219      obj.out1 = &a;220      obj.out2 = &b;221      obj.out3 = &c;222    }223 224    clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}225    clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}226    clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}227  }228}229 230 231namespace DestructorsShouldNotAffectReturnValues {232  class Dtor {233  public:234    ~Dtor() {235      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}236    }237  };238 239  void *allocate() {240    Dtor d;241    return malloc(4); // no-warning242  }243 244  void test() {245    // At one point we had an issue where the statements inside an246    // inlined destructor kept us from finding the return statement,247    // leading the analyzer to believe that the malloc'd memory had leaked.248    void *p = allocate();249    free(p); // no-warning250  }251}252 253namespace MultipleInheritanceVirtualDtors {254  class VirtualDtor {255  protected:256    virtual ~VirtualDtor() {257      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}258    }259  };260 261  class NonVirtualDtor {262  protected:263    ~NonVirtualDtor() {264      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}265    }266  };267 268  class SubclassA : public VirtualDtor, public NonVirtualDtor {269  public:270    virtual ~SubclassA() {}271  };272  class SubclassB : public NonVirtualDtor, public VirtualDtor {273  public:274    virtual ~SubclassB() {}275  };276 277  void test() {278    SubclassA a;279    SubclassB b;280  }281}282 283namespace ExplicitDestructorCall {284  class VirtualDtor {285  public:286    virtual ~VirtualDtor() {287      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}288    }289  };290  291  class Subclass : public VirtualDtor {292  public:293    virtual ~Subclass() {294      clang_analyzer_checkInlined(false); // no-warning295    }296  };297  298  void destroy(Subclass *obj) {299    obj->VirtualDtor::~VirtualDtor();300  }301}302 303 304namespace MultidimensionalArrays {305  void testArrayInvalidation() {306    int i = 42;307    int j = 42;308 309    {310      IntWrapper arr[2][2];311 312      // There should be no undefined value warnings here.313      clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{TRUE}}314      clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{TRUE}}315 316      arr[0][0].x = &i;317      arr[1][1].x = &j;318      clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}319      clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}320    }321 322    // The destructors should have invalidated i and j.323    clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}324    clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}325  }326}327 328namespace LifetimeExtension {329  struct IntWrapper {330	int x;331	IntWrapper(int y) : x(y) {}332	IntWrapper() {333      extern void use(int);334      use(x); // no-warning335	}336  };337 338  struct DerivedWrapper : public IntWrapper {339	DerivedWrapper(int y) : IntWrapper(y) {}340  };341 342  DerivedWrapper get() {343	return DerivedWrapper(1);344  }345 346  void test() {347	const DerivedWrapper &d = get(); // lifetime extended here348  }349 350 351  class SaveOnDestruct {352  public:353    static int lastOutput;354    int value;355 356    SaveOnDestruct();357    ~SaveOnDestruct() {358      lastOutput = value;359    }360  };361 362  void testSimple() {363    {364      const SaveOnDestruct &obj = SaveOnDestruct();365      if (obj.value != 42)366        return;367      // destructor called here368    }369 370    clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}371  }372 373  struct NRCheck {374    bool bool_;375    NRCheck():bool_(true) {}376    ~NRCheck() __attribute__((noreturn));377    operator bool() const { return bool_; }378  };379 380  struct CheckAutoDestructor {381    bool bool_;382    CheckAutoDestructor():bool_(true) {}383    operator bool() const { return bool_; }384  };385 386  struct CheckCustomDestructor {387    bool bool_;388    CheckCustomDestructor():bool_(true) {}389    ~CheckCustomDestructor();390    operator bool() const { return bool_; }391  };392 393  bool testUnnamedNR() {394    if (NRCheck())395      return true;396    return false;397  }398 399  bool testNamedNR() {400    if (NRCheck c = NRCheck())401      return true;402    return false;403  }404 405  bool testUnnamedAutoDestructor() {406    if (CheckAutoDestructor())407      return true;408    return false;409  }410 411  bool testNamedAutoDestructor() {412    if (CheckAutoDestructor c = CheckAutoDestructor())413      return true;414    return false;415  }416 417  bool testUnnamedCustomDestructor() {418    if (CheckCustomDestructor())419      return true;420    return false;421  }422 423  // This case used to cause an unexpected "Undefined or garbage value returned424  // to caller" warning425  bool testNamedCustomDestructor() {426    if (CheckCustomDestructor c = CheckCustomDestructor())427      return true;428    return false;429  }430 431  bool testMultipleTemporariesCustomDestructor() {432    if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))433      return true;434    return false;435  }436 437  class VirtualDtorBase {438  public:439    int value;440    virtual ~VirtualDtorBase() {}441  };442 443  class SaveOnVirtualDestruct : public VirtualDtorBase {444  public:445    static int lastOutput;446 447    SaveOnVirtualDestruct();448    virtual ~SaveOnVirtualDestruct() {449      lastOutput = value;450    }451  };452 453  void testVirtual() {454    {455      const VirtualDtorBase &obj = SaveOnVirtualDestruct();456      if (obj.value != 42)457        return;458      // destructor called here459    }460 461    clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}462  }463}464 465namespace NoReturn {466  struct NR {467    ~NR() __attribute__((noreturn));468  };469 470  void f(int **x) {471    NR nr;472  }473 474  void g() {475    int *x;476    f(&x);477    *x = 47; // no warning478  }479 480  void g2(int *x) {481    if (! x) NR();482    *x = 47; // no warning483  }484}485 486namespace PseudoDtor {487  template <typename T>488  void destroy(T &obj) {489    clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}490    obj.~T();491  }492 493  void test() {494    int i;495    destroy(i);496    clang_analyzer_eval(true); // expected-warning{{TRUE}}497  }498}499 500namespace Incomplete {501  class Foo; // expected-note{{forward declaration}}502  void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}503}504 505namespace TypeTraitExpr {506template <bool IsSimple, typename T>507struct copier {508  static void do_copy(T *dest, const T *src, unsigned count);509};510template <typename T, typename U>511void do_copy(T *dest, const U *src, unsigned count) {512  const bool IsSimple = __is_trivial(T) && __is_same(T, U);513  copier<IsSimple, T>::do_copy(dest, src, count);514}515struct NonTrivial {516  int *p;517  NonTrivial() : p(new int[1]) { p[0] = 0; }518  NonTrivial(const NonTrivial &other) {519    p = new int[1];520    do_copy(p, other.p, 1);521  }522  NonTrivial &operator=(const NonTrivial &other) {523    p = other.p;524    return *this;525  }526  ~NonTrivial() {527    delete[] p; // expected-warning {{release already released memory}}528  }529};530 531void f() {532  NonTrivial nt1;533  NonTrivial nt2(nt1);534  nt1 = nt2;535  clang_analyzer_eval(__is_trivial(NonTrivial)); // expected-warning{{FALSE}}536  clang_analyzer_eval(__alignof(NonTrivial) > 0); // expected-warning{{TRUE}}537}538}539 540namespace dtor_over_loc_concrete_int {541struct A {542  ~A() {}543};544 545struct B {546  A a;547  ~B() {}548};549 550struct C : A {551  ~C() {}552};553 554void testB() {555  B *b = (B *)-1;556  b->~B(); // no-crash557}558 559void testC() {560  C *c = (C *)-1;561  c->~C(); // no-crash562}563 564void testAutoDtor() {565  const A &a = *(A *)-1;566  // no-crash567}568} // namespace dtor_over_loc_concrete_int569 570// Test overriden new/delete operators571struct CustomOperators {572  void *operator new(size_t count) {573    return malloc(count);574  }575 576  void operator delete(void *addr) {577    free(addr);578  }579 580private:581  int i;582};583 584void compliant() {585  auto *a = new CustomOperators();586  delete a;587}588 589void overrideLeak() {590  auto *a = new CustomOperators();591} // expected-warning{{Potential leak of memory pointed to by 'a'}}592 593void overrideDoubleDelete() {594  auto *a = new CustomOperators();595  delete a;596  delete a; // expected-warning@577 {{Attempt to release already released memory}}597}598