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 6 class A { 7 protected: 8 int x; 9 }; 10 11 class B : public A { 12 public: 13 void f(); 14 }; 15 16 void B::f() { 17 x = 3; 18 } 19 20 21 class C : public B { 22 public: 23 void g() { 24 // This used to crash because we are upcasting through two bases. 25 x = 5; 26 } 27 }; 28 29 30 namespace VirtualBaseClasses { 31 class A { 32 protected: 33 int x; 34 }; 35 36 class B : public virtual A { 37 public: 38 int getX() { return x; } 39 }; 40 41 class C : public virtual A { 42 public: 43 void setX() { x = 42; } 44 }; 45 46 class D : public B, public C {}; 47 class DV : virtual public B, public C {}; 48 class DV2 : public B, virtual public C {}; 49 50 void test() { 51 D d; 52 d.setX(); 53 clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} 54 55 DV dv; 56 dv.setX(); 57 clang_analyzer_eval(dv.getX() == 42); // expected-warning{{TRUE}} 58 59 DV2 dv2; 60 dv2.setX(); 61 clang_analyzer_eval(dv2.getX() == 42); // expected-warning{{TRUE}} 62 } 63 64 65 // Make sure we're consistent about the offset of the A subobject within an 66 // Intermediate virtual base class. 67 class Padding1 { int unused; }; 68 class Padding2 { int unused; }; 69 class Intermediate : public Padding1, public A, public Padding2 {}; 70 71 class BI : public virtual Intermediate { 72 public: 73 int getX() { return x; } 74 }; 75 76 class CI : public virtual Intermediate { 77 public: 78 void setX() { x = 42; } 79 }; 80 81 class DI : public BI, public CI {}; 82 83 void testIntermediate() { 84 DI d; 85 d.setX(); 86 clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} 87 } 88 } 89 90 91 namespace DynamicVirtualUpcast { 92 class A { 93 public: 94 virtual ~A(); 95 }; 96 97 class B : virtual public A {}; 98 class C : virtual public B {}; 99 class D : virtual public C {}; 100 101 bool testCast(A *a) { 102 return dynamic_cast<B*>(a) && dynamic_cast<C*>(a); 103 } 104 105 void test() { 106 D d; 107 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 108 } 109 } 110 111 namespace DynamicMultipleInheritanceUpcast { 112 class B { 113 public: 114 virtual ~B(); 115 }; 116 class C { 117 public: 118 virtual ~C(); 119 }; 120 class D : public B, public C {}; 121 122 bool testCast(B *a) { 123 return dynamic_cast<C*>(a); 124 } 125 126 void test() { 127 D d; 128 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 129 } 130 131 132 class DV : virtual public B, virtual public C {}; 133 134 void testVirtual() { 135 DV d; 136 clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} 137 } 138 } 139 140 namespace LazyBindings { 141 struct Base { 142 int x; 143 }; 144 145 struct Derived : public Base { 146 int y; 147 }; 148 149 struct DoubleDerived : public Derived { 150 int z; 151 }; 152 153 int getX(const Base &obj) { 154 return obj.x; 155 } 156 157 int getY(const Derived &obj) { 158 return obj.y; 159 } 160 161 void testDerived() { 162 Derived d; 163 d.x = 1; 164 d.y = 2; 165 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 166 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 167 168 Base b(d); 169 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 170 171 Derived d2(d); 172 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 173 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 174 } 175 176 void testDoubleDerived() { 177 DoubleDerived d; 178 d.x = 1; 179 d.y = 2; 180 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 181 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 182 183 Base b(d); 184 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 185 186 Derived d2(d); 187 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 188 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 189 190 DoubleDerived d3(d); 191 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 192 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 193 } 194 195 namespace WithOffset { 196 struct Offset { 197 int padding; 198 }; 199 200 struct OffsetDerived : private Offset, public Base { 201 int y; 202 }; 203 204 struct DoubleOffsetDerived : public OffsetDerived { 205 int z; 206 }; 207 208 int getY(const OffsetDerived &obj) { 209 return obj.y; 210 } 211 212 void testDerived() { 213 OffsetDerived d; 214 d.x = 1; 215 d.y = 2; 216 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 217 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 218 219 Base b(d); 220 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 221 222 OffsetDerived d2(d); 223 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 224 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 225 } 226 227 void testDoubleDerived() { 228 DoubleOffsetDerived d; 229 d.x = 1; 230 d.y = 2; 231 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 232 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 233 234 Base b(d); 235 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 236 237 OffsetDerived d2(d); 238 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 239 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 240 241 DoubleOffsetDerived d3(d); 242 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 243 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 244 } 245 } 246 247 namespace WithVTable { 248 struct DerivedVTBL : public Base { 249 int y; 250 virtual void method(); 251 }; 252 253 struct DoubleDerivedVTBL : public DerivedVTBL { 254 int z; 255 }; 256 257 int getY(const DerivedVTBL &obj) { 258 return obj.y; 259 } 260 261 int getZ(const DoubleDerivedVTBL &obj) { 262 return obj.z; 263 } 264 265 void testDerived() { 266 DerivedVTBL d; 267 d.x = 1; 268 d.y = 2; 269 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 270 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 271 272 Base b(d); 273 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 274 275 #if CONSTRUCTORS 276 DerivedVTBL d2(d); 277 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 278 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 279 #endif 280 } 281 282 #if CONSTRUCTORS 283 void testDoubleDerived() { 284 DoubleDerivedVTBL d; 285 d.x = 1; 286 d.y = 2; 287 d.z = 3; 288 clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}} 289 clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}} 290 clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}} 291 292 Base b(d); 293 clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}} 294 295 DerivedVTBL d2(d); 296 clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}} 297 clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}} 298 299 DoubleDerivedVTBL d3(d); 300 clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}} 301 clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}} 302 clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}} 303 } 304 #endif 305 } 306 307 #if CONSTRUCTORS 308 namespace Nested { 309 struct NonTrivialCopy { 310 int padding; 311 NonTrivialCopy() {} 312 NonTrivialCopy(const NonTrivialCopy &) {} 313 }; 314 315 struct FullyDerived : private NonTrivialCopy, public Derived { 316 int z; 317 }; 318 319 struct Wrapper { 320 FullyDerived d; 321 int zz; 322 323 Wrapper(const FullyDerived &d) : d(d), zz(0) {} 324 }; 325 326 void test5() { 327 Wrapper w((FullyDerived())); 328 w.d.x = 1; 329 330 Wrapper w2(w); 331 clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}} 332 } 333 } 334 #endif 335 } 336 337 namespace Redeclaration { 338 class Base; 339 340 class Base { 341 public: 342 virtual int foo(); 343 int get() { return value; } 344 345 int value; 346 }; 347 348 class Derived : public Base { 349 public: 350 virtual int bar(); 351 }; 352 353 void test(Derived d) { 354 d.foo(); // don't crash 355 d.bar(); // sanity check 356 357 Base &b = d; 358 b.foo(); // don't crash 359 360 d.value = 42; // don't crash 361 clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}} 362 clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}} 363 } 364 }; 365 366