1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -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 class VirtualDtorBase { 378 public: 379 int value; 380 virtual ~VirtualDtorBase() {} 381 }; 382 383 class SaveOnVirtualDestruct : public VirtualDtorBase { 384 public: 385 static int lastOutput; 386 387 SaveOnVirtualDestruct(); 388 virtual ~SaveOnVirtualDestruct() { 389 lastOutput = value; 390 } 391 }; 392 393 void testVirtual() { 394 { 395 const VirtualDtorBase &obj = SaveOnVirtualDestruct(); 396 if (obj.value != 42) 397 return; 398 // destructor called here 399 } 400 401 clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}} 402 } 403 } 404 405 namespace NoReturn { 406 struct NR { 407 ~NR() __attribute__((noreturn)); 408 }; 409 410 void f(int **x) { 411 NR nr; 412 } 413 414 void g() { 415 int *x; 416 f(&x); 417 *x = 47; // no warning 418 } 419 } 420 421 namespace PseudoDtor { 422 template <typename T> 423 void destroy(T &obj) { 424 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 425 obj.~T(); 426 } 427 428 void test() { 429 int i; 430 destroy(i); 431 clang_analyzer_eval(true); // expected-warning{{TRUE}} 432 } 433 } 434