1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \ 2 // RUN: -analyzer-config eagerly-assume=false -verify %s 3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \ 4 // RUN: -analyzer-config eagerly-assume=false -verify %s 5 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \ 6 // RUN: -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG \ 7 // RUN: -analyzer-config eagerly-assume=false -verify=expected,no-elide %s 8 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \ 9 // RUN: -analyzer-config elide-constructors=false \ 10 // RUN: -analyzer-config eagerly-assume=false -verify %s 11 12 // Copy elision always occurs in C++17, otherwise it's under 13 // an on-by-default flag. 14 #if __cplusplus >= 201703L 15 #define ELIDE 1 16 #else 17 #ifndef NO_ELIDE_FLAG 18 #define ELIDE 1 19 #endif 20 #endif 21 22 void clang_analyzer_eval(bool); 23 void clang_analyzer_dump(int); 24 25 namespace variable_functional_cast_crash { 26 27 struct A { 28 A(int) {} 29 }; 30 31 void foo() { 32 A a = A(0); 33 } 34 35 struct B { 36 A a; 37 B(): a(A(0)) {} 38 }; 39 40 } // namespace variable_functional_cast_crash 41 42 43 namespace ctor_initializer { 44 45 struct S { 46 int x, y, z; 47 }; 48 49 struct T { 50 S s; 51 int w; 52 T(int w): s(), w(w) {} 53 }; 54 55 class C { 56 T t; 57 public: 58 C() : t(T(4)) { 59 S s = {1, 2, 3}; 60 t.s = s; 61 // FIXME: Should be TRUE regardless of copy elision. 62 clang_analyzer_eval(t.w == 4); 63 #ifdef ELIDE 64 // expected-warning@-2{{TRUE}} 65 #else 66 // expected-warning@-4{{UNKNOWN}} 67 #endif 68 } 69 }; 70 71 72 struct A { 73 int x; 74 A(): x(0) {} 75 ~A() {} 76 }; 77 78 struct B { 79 A a; 80 B() : a(A()) {} 81 }; 82 83 void foo() { 84 B b; 85 clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}} 86 } 87 88 } // namespace ctor_initializer 89 90 91 namespace elision_on_ternary_op_branches { 92 class C1 { 93 int x; 94 public: 95 C1(int x): x(x) {} 96 int getX() const { return x; } 97 ~C1(); 98 }; 99 100 class C2 { 101 int x; 102 int y; 103 public: 104 C2(int x, int y): x(x), y(y) {} 105 int getX() const { return x; } 106 int getY() const { return y; } 107 ~C2(); 108 }; 109 110 void foo(int coin) { 111 C1 c1 = coin ? C1(1) : C1(2); 112 if (coin) { 113 clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} 114 } else { 115 clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}} 116 } 117 C2 c2 = coin ? C2(3, 4) : C2(5, 6); 118 if (coin) { 119 clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}} 120 clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}} 121 } else { 122 clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}} 123 clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}} 124 } 125 } 126 } // namespace elision_on_ternary_op_branches 127 128 129 namespace address_vector_tests { 130 131 template <typename T> struct AddressVector { 132 T *buf[20]; 133 int len; 134 135 AddressVector() : len(0) {} 136 137 void push(T *t) { 138 buf[len] = t; 139 ++len; 140 } 141 }; 142 143 class ClassWithoutDestructor { 144 AddressVector<ClassWithoutDestructor> &v; 145 146 public: 147 ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) { 148 push(); 149 } 150 151 ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { push(); } 152 ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { push(); } 153 154 void push() { v.push(this); } 155 }; 156 157 ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) { 158 return ClassWithoutDestructor(v); 159 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 160 object of type 'ClassWithoutDestructor' is still \ 161 referred to by the caller variable 'v' upon returning to the caller}} 162 } 163 ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) { 164 return make1(v); 165 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 166 object of type 'ClassWithoutDestructor' is still \ 167 referred to by the caller variable 'v' upon returning to the caller}} 168 } 169 ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) { 170 return make2(v); 171 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 172 object of type 'ClassWithoutDestructor' is still \ 173 referred to by the caller variable 'v' upon returning to the caller}} 174 } 175 176 void testMultipleReturns() { 177 AddressVector<ClassWithoutDestructor> v; 178 ClassWithoutDestructor c = make3(v); 179 180 #if ELIDE 181 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}} 182 clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}} 183 #else 184 clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}} 185 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}} 186 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}} 187 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}} 188 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}} 189 clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}} 190 #endif 191 } 192 193 void consume(ClassWithoutDestructor c) { 194 c.push(); 195 // expected-warning@-1 {{Address of stack memory associated with local \ 196 variable 'c' is still referred to by the caller variable 'v' upon returning \ 197 to the caller}} 198 } 199 200 void testArgumentConstructorWithoutDestructor() { 201 AddressVector<ClassWithoutDestructor> v; 202 203 consume(make3(v)); 204 205 #if ELIDE 206 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} 207 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 208 #else 209 clang_analyzer_eval(v.len == 6); // expected-warning{{TRUE}} 210 clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}} 211 clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}} 212 clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}} 213 clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}} 214 // We forced a push() in consume(), let's see if the address here matches 215 // the address during construction. 216 clang_analyzer_eval(v.buf[4] == v.buf[5]); // expected-warning{{TRUE}} 217 #endif 218 } 219 220 class ClassWithDestructor { 221 AddressVector<ClassWithDestructor> &v; 222 223 public: 224 ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) { 225 push(); 226 } 227 228 ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); } 229 ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); } 230 231 ~ClassWithDestructor() { push(); } 232 233 void push() { v.push(this); } 234 }; 235 236 void testVariable() { 237 AddressVector<ClassWithDestructor> v; 238 { 239 ClassWithDestructor c = ClassWithDestructor(v); 240 // Check if the last destructor is an automatic destructor. 241 // A temporary destructor would have fired by now. 242 #if ELIDE 243 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}} 244 #else 245 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}} 246 #endif 247 } 248 #if ELIDE 249 // 0. Construct the variable. 250 // 1. Destroy the variable. 251 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} 252 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 253 #else 254 // 0. Construct the temporary. 255 // 1. Construct the variable. 256 // 2. Destroy the temporary. 257 // 3. Destroy the variable. 258 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}} 259 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} 260 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}} 261 #endif 262 } 263 264 struct TestCtorInitializer { 265 ClassWithDestructor c; 266 TestCtorInitializer(AddressVector<ClassWithDestructor> &refParam) 267 : c(ClassWithDestructor(refParam)) {} 268 }; 269 270 void testCtorInitializer() { 271 AddressVector<ClassWithDestructor> v; 272 { 273 TestCtorInitializer t(v); 274 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 275 object of type 'ClassWithDestructor' is still referred \ 276 to by the caller variable 'v' upon returning to the caller}} 277 // Check if the last destructor is an automatic destructor. 278 // A temporary destructor would have fired by now. 279 #if ELIDE 280 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}} 281 #else 282 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}} 283 #endif 284 } 285 #if ELIDE 286 // 0. Construct the member variable. 287 // 1. Destroy the member variable. 288 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} 289 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 290 #else 291 // 0. Construct the temporary. 292 // 1. Construct the member variable. 293 // 2. Destroy the temporary. 294 // 3. Destroy the member variable. 295 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}} 296 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} 297 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}} 298 #endif 299 } 300 301 302 ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) { 303 return ClassWithDestructor(v); 304 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 305 object of type 'ClassWithDestructor' is still referred \ 306 to by the caller variable 'v' upon returning to the caller}} 307 } 308 ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) { 309 return make1(v); 310 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 311 object of type 'ClassWithDestructor' is still referred \ 312 to by the caller variable 'v' upon returning to the caller}} 313 } 314 ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) { 315 return make2(v); 316 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 317 object of type 'ClassWithDestructor' is still referred \ 318 to by the caller variable 'v' upon returning to the caller}} 319 } 320 321 void testMultipleReturnsWithDestructors() { 322 AddressVector<ClassWithDestructor> v; 323 { 324 ClassWithDestructor c = make3(v); 325 // Check if the last destructor is an automatic destructor. 326 // A temporary destructor would have fired by now. 327 #if ELIDE 328 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}} 329 #else 330 clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}} 331 #endif 332 } 333 334 #if ELIDE 335 // 0. Construct the variable. Yes, constructor in make1() constructs 336 // the variable 'c'. 337 // 1. Destroy the variable. 338 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} 339 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 340 #else 341 // 0. Construct the temporary in make1(). 342 // 1. Construct the temporary in make2(). 343 // 2. Destroy the temporary in make1(). 344 // 3. Construct the temporary in make3(). 345 // 4. Destroy the temporary in make2(). 346 // 5. Construct the temporary here. 347 // 6. Destroy the temporary in make3(). 348 // 7. Construct the variable. 349 // 8. Destroy the temporary here. 350 // 9. Destroy the variable. 351 clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}} 352 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} 353 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}} 354 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}} 355 clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}} 356 clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}} 357 #endif 358 } 359 360 void consume(ClassWithDestructor c) { 361 c.push(); 362 // expected-warning@-1 {{Address of stack memory associated with local \ 363 variable 'c' is still referred to by the caller variable 'v' upon returning \ 364 to the caller}} 365 } 366 367 void testArgumentConstructorWithDestructor() { 368 AddressVector<ClassWithDestructor> v; 369 370 consume(make3(v)); 371 372 #if ELIDE 373 // 0. Construct the argument. 374 // 1. Forced push() in consume(). 375 // 2. Destroy the argument. 376 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}} 377 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} 378 clang_analyzer_eval(v.buf[1] == v.buf[2]); // expected-warning{{TRUE}} 379 #else 380 // 0. Construct the temporary in make1(). 381 // 1. Construct the temporary in make2(). 382 // 2. Destroy the temporary in make1(). 383 // 3. Construct the temporary in make3(). 384 // 4. Destroy the temporary in make2(). 385 // 5. Construct the temporary here. 386 // 6. Destroy the temporary in make3(). 387 // 7. Construct the argument. 388 // 8. Forced push() in consume(). 389 // 9. Destroy the argument. Notice the reverse order! 390 // 10. Destroy the temporary here. 391 clang_analyzer_eval(v.len == 11); // expected-warning{{TRUE}} 392 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} 393 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}} 394 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}} 395 clang_analyzer_eval(v.buf[5] == v.buf[10]); // expected-warning{{TRUE}} 396 clang_analyzer_eval(v.buf[7] == v.buf[8]); // expected-warning{{TRUE}} 397 clang_analyzer_eval(v.buf[8] == v.buf[9]); // expected-warning{{TRUE}} 398 #endif 399 } 400 401 struct Foo { 402 Foo(Foo **q) { 403 *q = this; 404 } 405 }; 406 407 Foo make1(Foo **r) { 408 return Foo(r); 409 // no-elide-warning@-1 {{Address of stack memory associated with temporary \ 410 object of type 'Foo' is still referred to by the caller \ 411 variable 'z' upon returning to the caller}} 412 } 413 414 void test_copy_elision() { 415 Foo *z; 416 // If the copy elided, 'z' points to 'tmp', otherwise it's a dangling pointer. 417 Foo tmp = make1(&z); 418 (void)tmp; 419 } 420 421 } // namespace address_vector_tests 422 423 namespace arg_directly_from_return_in_loop { 424 425 struct Result { 426 int value; 427 }; 428 429 Result create() { 430 return Result{10}; 431 } 432 433 int accessValue(Result r) { 434 return r.value; 435 } 436 437 void test() { 438 for (int i = 0; i < 3; ++i) { 439 int v = accessValue(create()); 440 if (i == 0) { 441 clang_analyzer_dump(v); // expected-warning {{10 S32b}} 442 } else { 443 clang_analyzer_dump(v); // expected-warning {{10 S32b}} 444 // was {{reg_${{[0-9]+}}<int r.value> }} for C++11 445 } 446 } 447 } 448 449 } // namespace arg_directly_from_return_in_loop 450