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