1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -verify %s 2 3 void clang_analyzer_eval(bool); 4 void clang_analyzer_checkInlined(bool); 5 6 typedef __typeof__(sizeof(int)) size_t; 7 extern "C" void *malloc(size_t); 8 9 // This is the standard placement new. operator new(size_t,void * __p)10inline void* operator new(size_t, void* __p) throw() 11 { 12 return __p; 13 } 14 15 16 class A { 17 public: getZero()18 int getZero() { return 0; } getNum()19 virtual int getNum() { return 0; } 20 }; 21 test(A & a)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 32 class One : public A { 33 public: getNum()34 virtual int getNum() { return 1; } 35 }; 36 testPathSensitivity(int x)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 58 namespace PureVirtualParent { 59 class Parent { 60 public: 61 virtual int pureVirtual() const = 0; callVirtual() const62 int callVirtual() const { 63 return pureVirtual(); 64 } 65 }; 66 67 class Child : public Parent { 68 public: pureVirtual() const69 virtual int pureVirtual() const { 70 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 71 return 42; 72 } 73 }; 74 testVirtual()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 84 namespace PR13569 { 85 class Parent { 86 protected: 87 int m_parent; 88 virtual int impl() const = 0; 89 Parent()90 Parent() : m_parent(0) {} 91 92 public: interface() const93 int interface() const { 94 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 95 return impl(); 96 } 97 }; 98 99 class Child : public Parent { 100 protected: impl() const101 virtual int impl() const { 102 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 103 return m_parent + m_child; 104 } 105 106 public: Child()107 Child() : m_child(0) {} 108 109 int m_child; 110 }; 111 testVirtual()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 testDevirtualizeToMiddle()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 132 namespace PR13569_virtual { 133 class Parent { 134 protected: 135 int m_parent; 136 virtual int impl() const = 0; 137 Parent()138 Parent() : m_parent(0) {} 139 140 public: interface() const141 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: impl() const149 virtual int impl() const { 150 clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} 151 return m_parent + m_child; 152 } 153 154 public: Child()155 Child() : m_child(0) {} 156 157 int m_child; 158 }; 159 testVirtual()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 testDevirtualizeToMiddle()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 180 namespace Invalidation { 181 struct X { touchInvalidation::X182 void touch(int &x) const { 183 x = 0; 184 } 185 186 void touch2(int &x) const; 187 touchVInvalidation::X188 virtual void touchV(int &x) const { 189 x = 0; 190 } 191 192 virtual void touchV2(int &x) const; 193 testInvalidation::X194 int test() const { 195 // We were accidentally not invalidating under -analyzer-ipa=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 207 namespace DefaultArgs { takesDefaultArgs(int i=42)208 int takesDefaultArgs(int i = 42) { 209 return -i; 210 } 211 testFunction()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 = 42; get(int i=value)220 int get(int i = value) { 221 return i; 222 } 223 }; 224 testMethod()225 void testMethod() { 226 Secret obj; 227 clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}} 228 229 // FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>. 230 clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} 231 232 // FIXME: Even if we constrain the variable, we still have a problem. 233 // See PR13385 or <rdar://problem/12156507>. 234 if (Secret::value != 42) 235 return; 236 clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} 237 clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} 238 } 239 } 240 241 namespace OperatorNew { 242 class IntWrapper { 243 public: 244 int value; 245 IntWrapper(int input)246 IntWrapper(int input) : value(input) { 247 // We don't want this constructor to be inlined unless we can actually 248 // use the proper region for operator new. 249 // See PR12014 and <rdar://problem/12180598>. 250 clang_analyzer_checkInlined(false); // no-warning 251 } 252 }; 253 test()254 void test() { 255 IntWrapper *obj = new IntWrapper(42); 256 // should be TRUE 257 clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} 258 } 259 testPlacement()260 void testPlacement() { 261 IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper))); 262 IntWrapper *alias = new (obj) IntWrapper(42); 263 264 clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}} 265 266 // should be TRUE 267 clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} 268 } 269 } 270 271 272 namespace VirtualWithSisterCasts { 273 // This entire set of tests exercises casts from sister classes and 274 // from classes outside the hierarchy, which can very much confuse 275 // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions. 276 // These examples used to cause crashes in +Asserts builds. 277 struct Parent { 278 virtual int foo(); 279 int x; 280 }; 281 282 struct A : Parent { fooVirtualWithSisterCasts::A283 virtual int foo() { return 42; } 284 }; 285 286 struct B : Parent { 287 virtual int foo(); 288 }; 289 290 struct Grandchild : public A {}; 291 292 struct Unrelated {}; 293 testDowncast(Parent * b)294 void testDowncast(Parent *b) { 295 A *a = (A *)(void *)b; 296 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 297 298 a->x = 42; 299 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 300 } 301 testRelated(B * b)302 void testRelated(B *b) { 303 A *a = (A *)(void *)b; 304 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 305 306 a->x = 42; 307 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 308 } 309 testUnrelated(Unrelated * b)310 void testUnrelated(Unrelated *b) { 311 A *a = (A *)(void *)b; 312 clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} 313 314 a->x = 42; 315 clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} 316 } 317 testCastViaNew(B * b)318 void testCastViaNew(B *b) { 319 Grandchild *g = new (b) Grandchild(); 320 // FIXME: We actually now have perfect type info because of 'new'. 321 // This should be TRUE. 322 clang_analyzer_eval(g->foo() == 42); // expected-warning{{UNKNOWN}} 323 324 g->x = 42; 325 clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}} 326 } 327 } 328