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