1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors -Wno-null-dereference -Wno-inaccessible-base -verify -analyzer-config eagerly-assume=false %s 2 3 void clang_analyzer_eval(bool); 4 void clang_analyzer_checkInlined(bool); 5 6 class A { 7 public: 8 ~A() { 9 int *x = 0; 10 *x = 3; // expected-warning{{Dereference of null pointer}} 11 } 12 }; 13 14 int main() { 15 A a; 16 } 17 18 19 typedef __typeof(sizeof(int)) size_t; 20 void *malloc(size_t); 21 void free(void *); 22 23 class SmartPointer { 24 void *X; 25 public: 26 SmartPointer(void *x) : X(x) {} 27 ~SmartPointer() { 28 free(X); 29 } 30 }; 31 32 void testSmartPointer() { 33 char *mem = (char*)malloc(4); 34 { 35 SmartPointer Deleter(mem); 36 // destructor called here 37 } 38 *mem = 0; // expected-warning{{Use of memory after it is freed}} 39 } 40 41 42 void doSomething(); 43 void testSmartPointer2() { 44 char *mem = (char*)malloc(4); 45 { 46 SmartPointer Deleter(mem); 47 // Remove dead bindings... 48 doSomething(); 49 // destructor called here 50 } 51 *mem = 0; // expected-warning{{Use of memory after it is freed}} 52 } 53 54 55 class Subclass : public SmartPointer { 56 public: 57 Subclass(void *x) : SmartPointer(x) {} 58 }; 59 60 void testSubclassSmartPointer() { 61 char *mem = (char*)malloc(4); 62 { 63 Subclass Deleter(mem); 64 // Remove dead bindings... 65 doSomething(); 66 // destructor called here 67 } 68 *mem = 0; // expected-warning{{Use of memory after it is freed}} 69 } 70 71 72 class MultipleInheritance : public Subclass, public SmartPointer { 73 public: 74 MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {} 75 }; 76 77 void testMultipleInheritance1() { 78 char *mem = (char*)malloc(4); 79 { 80 MultipleInheritance Deleter(mem, 0); 81 // Remove dead bindings... 82 doSomething(); 83 // destructor called here 84 } 85 *mem = 0; // expected-warning{{Use of memory after it is freed}} 86 } 87 88 void testMultipleInheritance2() { 89 char *mem = (char*)malloc(4); 90 { 91 MultipleInheritance Deleter(0, mem); 92 // Remove dead bindings... 93 doSomething(); 94 // destructor called here 95 } 96 *mem = 0; // expected-warning{{Use of memory after it is freed}} 97 } 98 99 void testMultipleInheritance3() { 100 char *mem = (char*)malloc(4); 101 { 102 MultipleInheritance Deleter(mem, mem); 103 // Remove dead bindings... 104 doSomething(); 105 // destructor called here 106 // expected-warning@28 {{Attempt to free released memory}} 107 } 108 } 109 110 111 class SmartPointerMember { 112 SmartPointer P; 113 public: 114 SmartPointerMember(void *x) : P(x) {} 115 }; 116 117 void testSmartPointerMember() { 118 char *mem = (char*)malloc(4); 119 { 120 SmartPointerMember Deleter(mem); 121 // Remove dead bindings... 122 doSomething(); 123 // destructor called here 124 } 125 *mem = 0; // expected-warning{{Use of memory after it is freed}} 126 } 127 128 129 struct IntWrapper { 130 IntWrapper() : x(0) {} 131 ~IntWrapper(); 132 int *x; 133 }; 134 135 void 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. 160 struct DefaultArg { 161 DefaultArg(int x = 0) {} 162 ~DefaultArg(); 163 }; 164 165 struct InheritsDefaultArg : DefaultArg { 166 InheritsDefaultArg() {} 167 virtual ~InheritsDefaultArg(); 168 }; 169 170 void testDefaultArg() { 171 InheritsDefaultArg a; 172 // Force a bug to be emitted. 173 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} 174 } 175 176 177 namespace 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 231 namespace 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-warning 242 } 243 244 void test() { 245 // At one point we had an issue where the statements inside an 246 // 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-warning 250 } 251 } 252 253 namespace 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 283 namespace 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-warning 295 } 296 }; 297 298 void destroy(Subclass *obj) { 299 obj->VirtualDtor::~VirtualDtor(); 300 } 301 } 302 303 304 namespace 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 328 namespace LifetimeExtension { 329 struct IntWrapper { 330 int x; 331 IntWrapper(int y) : x(y) {} 332 IntWrapper() { 333 extern void use(int); 334 use(x); // no-warning 335 } 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 here 348 } 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 here 368 } 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 returned 424 // to caller" warning 425 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 here 459 } 460 461 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}} 462 } 463 } 464 465 namespace 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 warning 478 } 479 480 void g2(int *x) { 481 if (! x) NR(); 482 *x = 47; // no warning 483 } 484 } 485 486 namespace 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 500 namespace Incomplete { 501 class Foo; // expected-note{{forward declaration}} 502 void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}} 503 } 504 505 namespace TypeTraitExpr { 506 template <bool IsSimple, typename T> 507 struct copier { 508 static void do_copy(T *dest, const T *src, unsigned count); 509 }; 510 template <typename T, typename U> 511 void 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 } 515 struct 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 {{free released memory}} 528 } 529 }; 530 531 void 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 540 namespace dtor_over_loc_concrete_int { 541 struct A { 542 ~A() {} 543 }; 544 545 struct B { 546 A a; 547 ~B() {} 548 }; 549 550 struct C : A { 551 ~C() {} 552 }; 553 554 void testB() { 555 B *b = (B *)-1; 556 b->~B(); // no-crash 557 } 558 559 void testC() { 560 C *c = (C *)-1; 561 c->~C(); // no-crash 562 } 563 564 void testAutoDtor() { 565 const A &a = *(A *)-1; 566 // no-crash 567 } 568 } // namespace dtor_over_loc_concrete_int 569 570 // Test overriden new/delete operators 571 struct 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 580 private: 581 int i; 582 }; 583 584 void compliant() { 585 auto *a = new CustomOperators(); 586 delete a; 587 } 588 589 void overrideLeak() { 590 auto *a = new CustomOperators(); 591 } // expected-warning{{Potential leak of memory pointed to by 'a'}} 592 593 void overrideDoubleDelete() { 594 auto *a = new CustomOperators(); 595 delete a; 596 delete a; // expected-warning@577 {{Attempt to free released memory}} 597 } 598