1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -Wno-inaccessible-base -verify %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 // Eventually these should be TRUE as well, but right now 144 // we can't handle array constructors. 145 clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}} 146 clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}} 147 148 arr[0].x = &i; 149 arr[1].x = &j; 150 clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}} 151 clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}} 152 } 153 154 // The destructors should have invalidated i and j. 155 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}} 156 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}} 157 } 158 159 160 161 // Don't crash on a default argument inside an initializer. 162 struct DefaultArg { 163 DefaultArg(int x = 0) {} 164 ~DefaultArg(); 165 }; 166 167 struct InheritsDefaultArg : DefaultArg { 168 InheritsDefaultArg() {} 169 virtual ~InheritsDefaultArg(); 170 }; 171 172 void testDefaultArg() { 173 InheritsDefaultArg a; 174 // Force a bug to be emitted. 175 *(char *)0 = 1; // expected-warning{{Dereference of null pointer}} 176 } 177 178 179 namespace DestructorVirtualCalls { 180 class A { 181 public: 182 int *out1, *out2, *out3; 183 184 virtual int get() { return 1; } 185 186 ~A() { 187 *out1 = get(); 188 } 189 }; 190 191 class B : public A { 192 public: 193 virtual int get() { return 2; } 194 195 ~B() { 196 *out2 = get(); 197 } 198 }; 199 200 class C : public B { 201 public: 202 virtual int get() { return 3; } 203 204 ~C() { 205 *out3 = get(); 206 } 207 }; 208 209 void test() { 210 int a, b, c; 211 212 // New scope for the C object. 213 { 214 C obj; 215 clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}} 216 217 // Sanity check for devirtualization. 218 A *base = &obj; 219 clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}} 220 221 obj.out1 = &a; 222 obj.out2 = &b; 223 obj.out3 = &c; 224 } 225 226 clang_analyzer_eval(a == 1); // expected-warning{{TRUE}} 227 clang_analyzer_eval(b == 2); // expected-warning{{TRUE}} 228 clang_analyzer_eval(c == 3); // expected-warning{{TRUE}} 229 } 230 } 231 232 233 namespace DestructorsShouldNotAffectReturnValues { 234 class Dtor { 235 public: 236 ~Dtor() { 237 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 238 } 239 }; 240 241 void *allocate() { 242 Dtor d; 243 return malloc(4); // no-warning 244 } 245 246 void test() { 247 // At one point we had an issue where the statements inside an 248 // inlined destructor kept us from finding the return statement, 249 // leading the analyzer to believe that the malloc'd memory had leaked. 250 void *p = allocate(); 251 free(p); // no-warning 252 } 253 } 254 255 namespace MultipleInheritanceVirtualDtors { 256 class VirtualDtor { 257 protected: 258 virtual ~VirtualDtor() { 259 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 260 } 261 }; 262 263 class NonVirtualDtor { 264 protected: 265 ~NonVirtualDtor() { 266 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 267 } 268 }; 269 270 class SubclassA : public VirtualDtor, public NonVirtualDtor { 271 public: 272 virtual ~SubclassA() {} 273 }; 274 class SubclassB : public NonVirtualDtor, public VirtualDtor { 275 public: 276 virtual ~SubclassB() {} 277 }; 278 279 void test() { 280 SubclassA a; 281 SubclassB b; 282 } 283 } 284 285 namespace ExplicitDestructorCall { 286 class VirtualDtor { 287 public: 288 virtual ~VirtualDtor() { 289 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 290 } 291 }; 292 293 class Subclass : public VirtualDtor { 294 public: 295 virtual ~Subclass() { 296 clang_analyzer_checkInlined(false); // no-warning 297 } 298 }; 299 300 void destroy(Subclass *obj) { 301 obj->VirtualDtor::~VirtualDtor(); 302 } 303 } 304 305 306 namespace MultidimensionalArrays { 307 void testArrayInvalidation() { 308 int i = 42; 309 int j = 42; 310 311 { 312 IntWrapper arr[2][2]; 313 314 // There should be no undefined value warnings here. 315 // Eventually these should be TRUE as well, but right now 316 // we can't handle array constructors. 317 clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}} 318 clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}} 319 320 arr[0][0].x = &i; 321 arr[1][1].x = &j; 322 clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}} 323 clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}} 324 } 325 326 // The destructors should have invalidated i and j. 327 clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}} 328 clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}} 329 } 330 } 331 332 namespace LifetimeExtension { 333 struct IntWrapper { 334 int x; 335 IntWrapper(int y) : x(y) {} 336 IntWrapper() { 337 extern void use(int); 338 use(x); // no-warning 339 } 340 }; 341 342 struct DerivedWrapper : public IntWrapper { 343 DerivedWrapper(int y) : IntWrapper(y) {} 344 }; 345 346 DerivedWrapper get() { 347 return DerivedWrapper(1); 348 } 349 350 void test() { 351 const DerivedWrapper &d = get(); // lifetime extended here 352 } 353 354 355 class SaveOnDestruct { 356 public: 357 static int lastOutput; 358 int value; 359 360 SaveOnDestruct(); 361 ~SaveOnDestruct() { 362 lastOutput = value; 363 } 364 }; 365 366 void testSimple() { 367 { 368 const SaveOnDestruct &obj = SaveOnDestruct(); 369 if (obj.value != 42) 370 return; 371 // destructor called here 372 } 373 374 clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}} 375 } 376 377 struct NRCheck { 378 bool bool_; 379 NRCheck():bool_(true) {} 380 ~NRCheck() __attribute__((noreturn)); 381 operator bool() const { return bool_; } 382 }; 383 384 struct CheckAutoDestructor { 385 bool bool_; 386 CheckAutoDestructor():bool_(true) {} 387 operator bool() const { return bool_; } 388 }; 389 390 struct CheckCustomDestructor { 391 bool bool_; 392 CheckCustomDestructor():bool_(true) {} 393 ~CheckCustomDestructor(); 394 operator bool() const { return bool_; } 395 }; 396 397 bool testUnnamedNR() { 398 if (NRCheck()) 399 return true; 400 return false; 401 } 402 403 bool testNamedNR() { 404 if (NRCheck c = NRCheck()) 405 return true; 406 return false; 407 } 408 409 bool testUnnamedAutoDestructor() { 410 if (CheckAutoDestructor()) 411 return true; 412 return false; 413 } 414 415 bool testNamedAutoDestructor() { 416 if (CheckAutoDestructor c = CheckAutoDestructor()) 417 return true; 418 return false; 419 } 420 421 bool testUnnamedCustomDestructor() { 422 if (CheckCustomDestructor()) 423 return true; 424 return false; 425 } 426 427 // This case used to cause an unexpected "Undefined or garbage value returned 428 // to caller" warning 429 bool testNamedCustomDestructor() { 430 if (CheckCustomDestructor c = CheckCustomDestructor()) 431 return true; 432 return false; 433 } 434 435 bool testMultipleTemporariesCustomDestructor() { 436 if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor())) 437 return true; 438 return false; 439 } 440 441 class VirtualDtorBase { 442 public: 443 int value; 444 virtual ~VirtualDtorBase() {} 445 }; 446 447 class SaveOnVirtualDestruct : public VirtualDtorBase { 448 public: 449 static int lastOutput; 450 451 SaveOnVirtualDestruct(); 452 virtual ~SaveOnVirtualDestruct() { 453 lastOutput = value; 454 } 455 }; 456 457 void testVirtual() { 458 { 459 const VirtualDtorBase &obj = SaveOnVirtualDestruct(); 460 if (obj.value != 42) 461 return; 462 // destructor called here 463 } 464 465 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}} 466 } 467 } 468 469 namespace NoReturn { 470 struct NR { 471 ~NR() __attribute__((noreturn)); 472 }; 473 474 void f(int **x) { 475 NR nr; 476 } 477 478 void g() { 479 int *x; 480 f(&x); 481 *x = 47; // no warning 482 } 483 484 void g2(int *x) { 485 if (! x) NR(); 486 *x = 47; // no warning 487 } 488 } 489 490 namespace PseudoDtor { 491 template <typename T> 492 void destroy(T &obj) { 493 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 494 obj.~T(); 495 } 496 497 void test() { 498 int i; 499 destroy(i); 500 clang_analyzer_eval(true); // expected-warning{{TRUE}} 501 } 502 } 503 504 namespace Incomplete { 505 class Foo; // expected-note{{forward declaration}} 506 void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}} 507 } 508 509 namespace TypeTraitExpr { 510 template <bool IsSimple, typename T> 511 struct copier { 512 static void do_copy(T *dest, const T *src, unsigned count); 513 }; 514 template <typename T, typename U> 515 void do_copy(T *dest, const U *src, unsigned count) { 516 const bool IsSimple = __is_trivial(T) && __is_same(T, U); 517 copier<IsSimple, T>::do_copy(dest, src, count); 518 } 519 struct NonTrivial { 520 int *p; 521 NonTrivial() : p(new int[1]) { p[0] = 0; } 522 NonTrivial(const NonTrivial &other) { 523 p = new int[1]; 524 do_copy(p, other.p, 1); 525 } 526 NonTrivial &operator=(const NonTrivial &other) { 527 p = other.p; 528 return *this; 529 } 530 ~NonTrivial() { 531 delete[] p; // expected-warning {{free released memory}} 532 } 533 }; 534 535 void f() { 536 NonTrivial nt1; 537 NonTrivial nt2(nt1); 538 nt1 = nt2; 539 clang_analyzer_eval(__is_trivial(NonTrivial)); // expected-warning{{FALSE}} 540 clang_analyzer_eval(__alignof(NonTrivial) > 0); // expected-warning{{TRUE}} 541 } 542 } 543