1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s 2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s 3 4 void clang_analyzer_eval(bool); 5 void clang_analyzer_checkInlined(bool); 6 7 class A { 8 protected: 9 int x; 10 }; 11 12 class B : public A { 13 public: 14 void f(); 15 }; 16 17 void B::f() { 18 x = 3; 19 } 20 21 22 class C : public B { 23 public: 24 void g() { 25 // This used to crash because we are upcasting through two bases. 26 x = 5; 27 } 28 }; 29 30 31 namespace VirtualBaseClasses { 32 class A { 33 protected: 34 int x; 35 }; 36 37 class B : public virtual A { 38 public: 39 int getX() { return x; } 40 }; 41 42 class C : public virtual A { 43 public: 44 void setX() { x = 42; } 45 }; 46 47 class D : public B, public C {}; 48 class DV : virtual public B, public C {}; 49 class DV2 : public B, virtual public C {}; 50 51 void test() { 52 D d; 53 d.setX(); 54 clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} 55 56 DV dv; 57 dv.setX(); 58 clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}} 59 60 DV2 dv2; 61 dv2.setX(); 62 clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}} 63 } 64 65 66 // Make sure we're consistent about the offset of the A subobject within an 67 // Intermediate virtual base class. 68 class Padding1 { int unused; }; 69 class Padding2 { int unused; }; 70 class Intermediate : public Padding1, public A, public Padding2 {}; 71 72 class BI : public virtual Intermediate { 73 public: 74 int getX() { return x; } 75 }; 76 77 class CI : public virtual Intermediate { 78 public: 79 void setX() { x = 42; } 80 }; 81 82 class DI : public BI, public CI {}; 83 84 void testIntermediate() { 85 DI d; 86 d.setX(); 87 clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} 88 } 89 } 90 91 92 namespace DynamicVirtualUpcast { 93 class A { 94 public: 95 virtual ~A(); 96 }; 97 98 class B : virtual public A {}; 99 class C : virtual public B {}; 100 class D : virtual public C {}; 101 102 bool testCast(A *a) { 103 return dynamic_cast<B*>(a) && dynamic_cast<C*>(a); 104 } 105 106 void test() { 107 D d; 108 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 109 } 110 } 111 112 namespace DynamicMultipleInheritanceUpcast { 113 class B { 114 public: 115 virtual ~B(); 116 }; 117 class C { 118 public: 119 virtual ~C(); 120 }; 121 class D : public B, public C {}; 122 123 bool testCast(B *a) { 124 return dynamic_cast<C*>(a); 125 } 126 127 void test() { 128 D d; 129 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 130 } 131 132 133 class DV : virtual public B, virtual public C {}; 134 135 void testVirtual() { 136 DV d; 137 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 138 } 139 } 140 141 namespace LazyBindings { 142 struct Base { 143 int x; 144 }; 145 146 struct Derived : public Base { 147 int y; 148 }; 149 150 struct DoubleDerived : public Derived { 151 int z; 152 }; 153 154 int getX(const Base &obj) { 155 return obj.x; 156 } 157 158 int getY(const Derived &obj) { 159 return obj.y; 160 } 161 162 void testDerived() { 163 Derived d; 164 d.x = 1; 165 d.y = 2; 166 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 167 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 168 169 Base b(d); 170 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 171 172 Derived d2(d); 173 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 174 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 175 } 176 177 void testDoubleDerived() { 178 DoubleDerived d; 179 d.x = 1; 180 d.y = 2; 181 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 182 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 183 184 Base b(d); 185 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 186 187 Derived d2(d); 188 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 189 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 190 191 DoubleDerived d3(d); 192 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 193 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 194 } 195 196 namespace WithOffset { 197 struct Offset { 198 int padding; 199 }; 200 201 struct OffsetDerived : private Offset, public Base { 202 int y; 203 }; 204 205 struct DoubleOffsetDerived : public OffsetDerived { 206 int z; 207 }; 208 209 int getY(const OffsetDerived &obj) { 210 return obj.y; 211 } 212 213 void testDerived() { 214 OffsetDerived d; 215 d.x = 1; 216 d.y = 2; 217 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 218 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 219 220 Base b(d); 221 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 222 223 OffsetDerived d2(d); 224 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 225 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 226 } 227 228 void testDoubleDerived() { 229 DoubleOffsetDerived d; 230 d.x = 1; 231 d.y = 2; 232 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 233 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 234 235 Base b(d); 236 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 237 238 OffsetDerived d2(d); 239 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 240 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 241 242 DoubleOffsetDerived d3(d); 243 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 244 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 245 } 246 } 247 248 namespace WithVTable { 249 struct DerivedVTBL : public Base { 250 int y; 251 virtual void method(); 252 }; 253 254 struct DoubleDerivedVTBL : public DerivedVTBL { 255 int z; 256 }; 257 258 int getY(const DerivedVTBL &obj) { 259 return obj.y; 260 } 261 262 int getZ(const DoubleDerivedVTBL &obj) { 263 return obj.z; 264 } 265 266 void testDerived() { 267 DerivedVTBL d; 268 d.x = 1; 269 d.y = 2; 270 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 271 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 272 273 Base b(d); 274 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 275 276 #if CONSTRUCTORS 277 DerivedVTBL d2(d); 278 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 279 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 280 #endif 281 } 282 283 #if CONSTRUCTORS 284 void testDoubleDerived() { 285 DoubleDerivedVTBL d; 286 d.x = 1; 287 d.y = 2; 288 d.z = 3; 289 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 290 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 291 clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}} 292 293 Base b(d); 294 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 295 296 DerivedVTBL d2(d); 297 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 298 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 299 300 DoubleDerivedVTBL d3(d); 301 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 302 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 303 clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}} 304 } 305 #endif 306 } 307 308 #if CONSTRUCTORS 309 namespace Nested { 310 struct NonTrivialCopy { 311 int padding; 312 NonTrivialCopy() {} 313 NonTrivialCopy(const NonTrivialCopy &) {} 314 }; 315 316 struct FullyDerived : private NonTrivialCopy, public Derived { 317 int z; 318 }; 319 320 struct Wrapper { 321 FullyDerived d; 322 int zz; 323 324 Wrapper(const FullyDerived &d) : d(d), zz(0) {} 325 }; 326 327 void test5() { 328 Wrapper w((FullyDerived())); 329 w.d.x = 1; 330 331 Wrapper w2(w); 332 clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}} 333 } 334 } 335 #endif 336 } 337 338 namespace Redeclaration { 339 class Base; 340 341 class Base { 342 public: 343 virtual int foo(); 344 int get() { return value; } 345 346 int value; 347 }; 348 349 class Derived : public Base { 350 public: 351 virtual int bar(); 352 }; 353 354 void test(Derived d) { 355 d.foo(); // don't crash 356 d.bar(); // sanity check 357 358 Base &b = d; 359 b.foo(); // don't crash 360 361 d.value = 42; // don't crash 362 clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}} 363 clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}} 364 } 365 }; 366 367 namespace PR15394 { 368 namespace Original { 369 class Base { 370 public: 371 virtual int f() = 0; 372 int i; 373 }; 374 375 class Derived1 : public Base { 376 public: 377 int j; 378 }; 379 380 class Derived2 : public Derived1 { 381 public: 382 virtual int f() { 383 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 384 return i + j; 385 } 386 }; 387 388 void testXXX() { 389 Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2); 390 d1p->i = 1; 391 d1p->j = 2; 392 clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} 393 } 394 } 395 396 namespace VirtualInDerived { 397 class Base { 398 public: 399 int i; 400 }; 401 402 class Derived1 : public Base { 403 public: 404 virtual int f() = 0; 405 int j; 406 }; 407 408 class Derived2 : public Derived1 { 409 public: 410 virtual int f() { 411 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 412 return i + j; 413 } 414 }; 415 416 void test() { 417 Derived1 *d1p = reinterpret_cast<Derived1*>(new Derived2); 418 d1p->i = 1; 419 d1p->j = 2; 420 clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} 421 } 422 } 423 424 namespace NoCast { 425 class Base { 426 public: 427 int i; 428 }; 429 430 class Derived1 : public Base { 431 public: 432 virtual int f() = 0; 433 int j; 434 }; 435 436 class Derived2 : public Derived1 { 437 public: 438 virtual int f() { 439 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 440 return i + j; 441 } 442 }; 443 444 void test() { 445 Derived1 *d1p = new Derived2; 446 d1p->i = 1; 447 d1p->j = 2; 448 clang_analyzer_eval(d1p->f() == 3); // expected-warning{{TRUE}} 449 } 450 } 451 }; 452 453 namespace Bug16309 { 454 struct Incomplete; 455 456 struct Base { virtual ~Base(); }; 457 458 struct Derived : public Base { int x; }; 459 460 void* f(Incomplete *i) { 461 Base *b = reinterpret_cast<Base *>(i); 462 // This used to crash because of the reinterpret_cast above. 463 Derived *d = dynamic_cast<Derived *>(b); 464 return d; 465 } 466 467 // And check that reinterpret+dynamic casts work correctly after the fix. 468 void g() { 469 Derived d; 470 d.x = 47; 471 Base *b = &d; 472 Incomplete *i = reinterpret_cast<Incomplete *>(b); 473 Base *b2 = reinterpret_cast<Base *>(i); 474 Derived *d2 = dynamic_cast<Derived *>(b2); 475 clang_analyzer_eval(d2->x == 47); // expected-warning{{TRUE}} 476 } 477 } 478