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