inline.cpp revision 4b75085f5669efc6407c662b5686361624c3ff2f
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -verify %s 2 3void clang_analyzer_eval(bool); 4void clang_analyzer_checkInlined(bool); 5 6typedef __typeof__(sizeof(int)) size_t; 7extern "C" void *malloc(size_t); 8 9// This is the standard placement new. 10inline void* operator new(size_t, void* __p) throw() 11{ 12 return __p; 13} 14 15 16class A { 17public: 18 int getZero() { return 0; } 19 virtual int getNum() { return 0; } 20}; 21 22void test(A &a) { 23 clang_analyzer_eval(a.getZero() == 0); // expected-warning{{TRUE}} 24 clang_analyzer_eval(a.getNum() == 0); // expected-warning{{UNKNOWN}} 25 26 A copy(a); 27 clang_analyzer_eval(copy.getZero() == 0); // expected-warning{{TRUE}} 28 clang_analyzer_eval(copy.getNum() == 0); // expected-warning{{TRUE}} 29} 30 31 32class One : public A { 33public: 34 virtual int getNum() { return 1; } 35}; 36 37void testPathSensitivity(int x) { 38 A a; 39 One b; 40 41 A *ptr; 42 switch (x) { 43 case 0: 44 ptr = &a; 45 break; 46 case 1: 47 ptr = &b; 48 break; 49 default: 50 return; 51 } 52 53 // This should be true on both branches. 54 clang_analyzer_eval(ptr->getNum() == x); // expected-warning {{TRUE}} 55} 56 57 58namespace PureVirtualParent { 59 class Parent { 60 public: 61 virtual int pureVirtual() const = 0; 62 int callVirtual() const { 63 return pureVirtual(); 64 } 65 }; 66 67 class Child : public Parent { 68 public: 69 virtual int pureVirtual() const { 70 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 71 return 42; 72 } 73 }; 74 75 void testVirtual() { 76 Child x; 77 78 clang_analyzer_eval(x.pureVirtual() == 42); // expected-warning{{TRUE}} 79 clang_analyzer_eval(x.callVirtual() == 42); // expected-warning{{TRUE}} 80 } 81} 82 83 84namespace PR13569 { 85 class Parent { 86 protected: 87 int m_parent; 88 virtual int impl() const = 0; 89 90 Parent() : m_parent(0) {} 91 92 public: 93 int interface() const { 94 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 95 return impl(); 96 } 97 }; 98 99 class Child : public Parent { 100 protected: 101 virtual int impl() const { 102 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 103 return m_parent + m_child; 104 } 105 106 public: 107 Child() : m_child(0) {} 108 109 int m_child; 110 }; 111 112 void testVirtual() { 113 Child x; 114 x.m_child = 42; 115 116 // Don't crash when inlining and devirtualizing. 117 x.interface(); 118 } 119 120 121 class Grandchild : public Child {}; 122 123 void testDevirtualizeToMiddle() { 124 Grandchild x; 125 x.m_child = 42; 126 127 // Don't crash when inlining and devirtualizing. 128 x.interface(); 129 } 130} 131 132namespace PR13569_virtual { 133 class Parent { 134 protected: 135 int m_parent; 136 virtual int impl() const = 0; 137 138 Parent() : m_parent(0) {} 139 140 public: 141 int interface() const { 142 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 143 return impl(); 144 } 145 }; 146 147 class Child : virtual public Parent { 148 protected: 149 virtual int impl() const { 150 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 151 return m_parent + m_child; 152 } 153 154 public: 155 Child() : m_child(0) {} 156 157 int m_child; 158 }; 159 160 void testVirtual() { 161 Child x; 162 x.m_child = 42; 163 164 // Don't crash when inlining and devirtualizing. 165 x.interface(); 166 } 167 168 169 class Grandchild : virtual public Child {}; 170 171 void testDevirtualizeToMiddle() { 172 Grandchild x; 173 x.m_child = 42; 174 175 // Don't crash when inlining and devirtualizing. 176 x.interface(); 177 } 178} 179 180namespace Invalidation { 181 struct X { 182 void touch(int &x) const { 183 x = 0; 184 } 185 186 void touch2(int &x) const; 187 188 virtual void touchV(int &x) const { 189 x = 0; 190 } 191 192 virtual void touchV2(int &x) const; 193 194 int test() const { 195 // We were accidentally not invalidating under inlining 196 // at one point for virtual methods with visible definitions. 197 int a, b, c, d; 198 touch(a); 199 touch2(b); 200 touchV(c); 201 touchV2(d); 202 return a + b + c + d; // no-warning 203 } 204 }; 205} 206 207namespace DefaultArgs { 208 int takesDefaultArgs(int i = 42) { 209 return -i; 210 } 211 212 void testFunction() { 213 clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}} 214 clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}} 215 } 216 217 class Secret { 218 public: 219 static const int value = 40 + 2; 220 int get(int i = value) { 221 return i; 222 } 223 }; 224 225 void testMethod() { 226 Secret obj; 227 clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}} 228 clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}} 229 clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} 230 } 231 232 enum ABC { 233 A = 0, 234 B = 1, 235 C = 2 236 }; 237 238 int enumUser(ABC input = B) { 239 return static_cast<int>(input); 240 } 241 242 void testEnum() { 243 clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}} 244 clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}} 245 } 246 247 248 int exprUser(int input = 2 * 4) { 249 return input; 250 } 251 252 int complicatedExprUser(int input = 2 * Secret::value) { 253 return input; 254 } 255 256 void testExprs() { 257 clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}} 258 clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}} 259 260 clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}} 261 clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}} 262 } 263 264 int defaultReference(const int &input = 42) { 265 return -input; 266 } 267 int defaultReferenceZero(const int &input = 0) { 268 return -input; 269 } 270 271 void testReference() { 272 clang_analyzer_eval(defaultReference(1) == -1); // expected-warning{{TRUE}} 273 clang_analyzer_eval(defaultReference() == -42); // expected-warning{{TRUE}} 274 275 clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}} 276 clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}} 277} 278 279 double defaultFloatReference(const double &i = 42) { 280 return -i; 281 } 282 double defaultFloatReferenceZero(const double &i = 0) { 283 return -i; 284 } 285 286 void testFloatReference() { 287 clang_analyzer_eval(defaultFloatReference(1) == -1); // expected-warning{{UNKNOWN}} 288 clang_analyzer_eval(defaultFloatReference() == -42); // expected-warning{{UNKNOWN}} 289 290 clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}} 291 clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}} 292 } 293} 294 295namespace OperatorNew { 296 class IntWrapper { 297 public: 298 int value; 299 300 IntWrapper(int input) : value(input) { 301 // We don't want this constructor to be inlined unless we can actually 302 // use the proper region for operator new. 303 // See PR12014 and <rdar://problem/12180598>. 304 clang_analyzer_checkInlined(false); // no-warning 305 } 306 }; 307 308 void test() { 309 IntWrapper *obj = new IntWrapper(42); 310 // should be TRUE 311 clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} 312 delete obj; 313 } 314 315 void testPlacement() { 316 IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper))); 317 IntWrapper *alias = new (obj) IntWrapper(42); 318 319 clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}} 320 321 // should be TRUE 322 clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} 323 } 324} 325 326 327namespace VirtualWithSisterCasts { 328 // This entire set of tests exercises casts from sister classes and 329 // from classes outside the hierarchy, which can very much confuse 330 // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions. 331 // These examples used to cause crashes in +Asserts builds. 332 struct Parent { 333 virtual int foo(); 334 int x; 335 }; 336 337 struct A : Parent { 338 virtual int foo() { return 42; } 339 }; 340 341 struct B : Parent { 342 virtual int foo(); 343 }; 344 345 struct Grandchild : public A {}; 346 347 struct Unrelated {}; 348 349 void testDowncast(Parent *b) { 350 A *a = (A *)(void *)b; 351 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 352 353 a->x = 42; 354 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 355 } 356 357 void testRelated(B *b) { 358 A *a = (A *)(void *)b; 359 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 360 361 a->x = 42; 362 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 363 } 364 365 void testUnrelated(Unrelated *b) { 366 A *a = (A *)(void *)b; 367 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 368 369 a->x = 42; 370 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 371 } 372 373 void testCastViaNew(B *b) { 374 Grandchild *g = new (b) Grandchild(); 375 clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}} 376 377 g->x = 42; 378 clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}} 379 } 380} 381 382 383namespace QualifiedCalls { 384 void test(One *object) { 385 // This uses the One class from the top of the file. 386 clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}} 387 clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}} 388 clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}} 389 390 // getZero is non-virtual. 391 clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}} 392 clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}} 393 clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}} 394} 395} 396 397 398namespace rdar12409977 { 399 struct Base { 400 int x; 401 }; 402 403 struct Parent : public Base { 404 virtual Parent *vGetThis(); 405 Parent *getThis() { return vGetThis(); } 406 }; 407 408 struct Child : public Parent { 409 virtual Child *vGetThis() { return this; } 410 }; 411 412 void test() { 413 Child obj; 414 obj.x = 42; 415 416 // Originally, calling a devirtualized method with a covariant return type 417 // caused a crash because the return value had the wrong type. When we then 418 // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of 419 // the object region and we get an assertion failure. 420 clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}} 421 } 422} 423