TestNoRefcountedInsideLambdas.cpp (17292B)
1 #include <mozilla/StaticAnalysisFunctions.h> 2 3 #include <functional> 4 #define MOZ_STRONG_REF 5 #define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) 6 7 // Ensure that warnings about returning stack addresses of local variables are 8 // errors, so our `expected-error` annotations below work correctly. 9 #pragma GCC diagnostic error "-Wreturn-stack-address" 10 11 struct RefCountedBase { 12 void AddRef(); 13 void Release(); 14 }; 15 16 template <class T> 17 struct SmartPtr { 18 SmartPtr(); 19 MOZ_IMPLICIT SmartPtr(T*); 20 T* MOZ_STRONG_REF t; 21 T* operator->() const; 22 }; 23 24 struct R : RefCountedBase { 25 void method(); 26 private: 27 void privateMethod(); 28 }; 29 30 void take(...); 31 void foo() { 32 R* ptr; 33 SmartPtr<R> sp; 34 take([&](R* argptr) { 35 R* localptr; 36 ptr->method(); 37 argptr->method(); 38 localptr->method(); 39 }); 40 take([&](SmartPtr<R> argsp) { 41 SmartPtr<R> localsp; 42 sp->method(); 43 argsp->method(); 44 localsp->method(); 45 }); 46 take([&](R* argptr) { 47 R* localptr; 48 take(ptr); 49 take(argptr); 50 take(localptr); 51 }); 52 take([&](SmartPtr<R> argsp) { 53 SmartPtr<R> localsp; 54 take(sp); 55 take(argsp); 56 take(localsp); 57 }); 58 take([=](R* argptr) { 59 R* localptr; 60 ptr->method(); 61 argptr->method(); 62 localptr->method(); 63 }); 64 take([=](SmartPtr<R> argsp) { 65 SmartPtr<R> localsp; 66 sp->method(); 67 argsp->method(); 68 localsp->method(); 69 }); 70 take([=](R* argptr) { 71 R* localptr; 72 take(ptr); 73 take(argptr); 74 take(localptr); 75 }); 76 take([=](SmartPtr<R> argsp) { 77 SmartPtr<R> localsp; 78 take(sp); 79 take(argsp); 80 take(localsp); 81 }); 82 take([ptr](R* argptr) { 83 R* localptr; 84 ptr->method(); 85 argptr->method(); 86 localptr->method(); 87 }); 88 take([sp](SmartPtr<R> argsp) { 89 SmartPtr<R> localsp; 90 sp->method(); 91 argsp->method(); 92 localsp->method(); 93 }); 94 take([ptr](R* argptr) { 95 R* localptr; 96 take(ptr); 97 take(argptr); 98 take(localptr); 99 }); 100 take([sp](SmartPtr<R> argsp) { 101 SmartPtr<R> localsp; 102 take(sp); 103 take(argsp); 104 take(localsp); 105 }); 106 take([&ptr](R* argptr) { 107 R* localptr; 108 ptr->method(); 109 argptr->method(); 110 localptr->method(); 111 }); 112 take([&sp](SmartPtr<R> argsp) { 113 SmartPtr<R> localsp; 114 sp->method(); 115 argsp->method(); 116 localsp->method(); 117 }); 118 take([&ptr](R* argptr) { 119 R* localptr; 120 take(ptr); 121 take(argptr); 122 take(localptr); 123 }); 124 take([&sp](SmartPtr<R> argsp) { 125 SmartPtr<R> localsp; 126 take(sp); 127 take(argsp); 128 take(localsp); 129 }); 130 } 131 132 void b() { 133 R* ptr; 134 SmartPtr<R> sp; 135 std::function<void(R*)>([&](R* argptr) { 136 R* localptr; 137 ptr->method(); 138 argptr->method(); 139 localptr->method(); 140 }); 141 std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) { 142 SmartPtr<R> localsp; 143 sp->method(); 144 argsp->method(); 145 localsp->method(); 146 }); 147 std::function<void(R*)>([&](R* argptr) { 148 R* localptr; 149 take(ptr); 150 take(argptr); 151 take(localptr); 152 }); 153 std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) { 154 SmartPtr<R> localsp; 155 take(sp); 156 take(argsp); 157 take(localsp); 158 }); 159 std::function<void(R*)>([=](R* argptr) { 160 R* localptr; 161 ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 162 argptr->method(); 163 localptr->method(); 164 }); 165 std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) { 166 SmartPtr<R> localsp; 167 sp->method(); 168 argsp->method(); 169 localsp->method(); 170 }); 171 std::function<void(R*)>([=](R* argptr) { 172 R* localptr; 173 take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 174 take(argptr); 175 take(localptr); 176 }); 177 std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) { 178 SmartPtr<R> localsp; 179 take(sp); 180 take(argsp); 181 take(localsp); 182 }); 183 std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 184 R* localptr; 185 ptr->method(); 186 argptr->method(); 187 localptr->method(); 188 }); 189 std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) { 190 SmartPtr<R> localsp; 191 sp->method(); 192 argsp->method(); 193 localsp->method(); 194 }); 195 std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 196 R* localptr; 197 take(ptr); 198 take(argptr); 199 take(localptr); 200 }); 201 std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) { 202 SmartPtr<R> localsp; 203 take(sp); 204 take(argsp); 205 take(localsp); 206 }); 207 std::function<void(R*)>([&ptr](R* argptr) { 208 R* localptr; 209 ptr->method(); 210 argptr->method(); 211 localptr->method(); 212 }); 213 std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) { 214 SmartPtr<R> localsp; 215 sp->method(); 216 argsp->method(); 217 localsp->method(); 218 }); 219 std::function<void(R*)>([&ptr](R* argptr) { 220 R* localptr; 221 take(ptr); 222 take(argptr); 223 take(localptr); 224 }); 225 std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) { 226 SmartPtr<R> localsp; 227 take(sp); 228 take(argsp); 229 take(localsp); 230 }); 231 } 232 233 // These tests would check c++14 deduced return types, if they were supported in 234 // our codebase. They are being kept here for convenience in the future if we do 235 // add support for c++14 deduced return types 236 #if 0 237 auto d1() { 238 R* ptr; 239 SmartPtr<R> sp; 240 return ([&](R* argptr) { 241 R* localptr; 242 ptr->method(); 243 argptr->method(); 244 localptr->method(); 245 }); 246 } 247 auto d2() { 248 R* ptr; 249 SmartPtr<R> sp; 250 return ([&](SmartPtr<R> argsp) { 251 SmartPtr<R> localsp; 252 sp->method(); 253 argsp->method(); 254 localsp->method(); 255 }); 256 } 257 auto d3() { 258 R* ptr; 259 SmartPtr<R> sp; 260 return ([&](R* argptr) { 261 R* localptr; 262 take(ptr); 263 take(argptr); 264 take(localptr); 265 }); 266 } 267 auto d4() { 268 R* ptr; 269 SmartPtr<R> sp; 270 return ([&](SmartPtr<R> argsp) { 271 SmartPtr<R> localsp; 272 take(sp); 273 take(argsp); 274 take(localsp); 275 }); 276 } 277 auto d5() { 278 R* ptr; 279 SmartPtr<R> sp; 280 return ([=](R* argptr) { 281 R* localptr; 282 ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 283 argptr->method(); 284 localptr->method(); 285 }); 286 } 287 auto d6() { 288 R* ptr; 289 SmartPtr<R> sp; 290 return ([=](SmartPtr<R> argsp) { 291 SmartPtr<R> localsp; 292 sp->method(); 293 argsp->method(); 294 localsp->method(); 295 }); 296 } 297 auto d8() { 298 R* ptr; 299 SmartPtr<R> sp; 300 return ([=](R* argptr) { 301 R* localptr; 302 take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 303 take(argptr); 304 take(localptr); 305 }); 306 } 307 auto d9() { 308 R* ptr; 309 SmartPtr<R> sp; 310 return ([=](SmartPtr<R> argsp) { 311 SmartPtr<R> localsp; 312 take(sp); 313 take(argsp); 314 take(localsp); 315 }); 316 } 317 auto d10() { 318 R* ptr; 319 SmartPtr<R> sp; 320 return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 321 R* localptr; 322 ptr->method(); 323 argptr->method(); 324 localptr->method(); 325 }); 326 } 327 auto d11() { 328 R* ptr; 329 SmartPtr<R> sp; 330 return ([sp](SmartPtr<R> argsp) { 331 SmartPtr<R> localsp; 332 sp->method(); 333 argsp->method(); 334 localsp->method(); 335 }); 336 } 337 auto d12() { 338 R* ptr; 339 SmartPtr<R> sp; 340 return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 341 R* localptr; 342 take(ptr); 343 take(argptr); 344 take(localptr); 345 }); 346 } 347 auto d13() { 348 R* ptr; 349 SmartPtr<R> sp; 350 return ([sp](SmartPtr<R> argsp) { 351 SmartPtr<R> localsp; 352 take(sp); 353 take(argsp); 354 take(localsp); 355 }); 356 } 357 auto d14() { 358 R* ptr; 359 SmartPtr<R> sp; 360 return ([&ptr](R* argptr) { 361 R* localptr; 362 ptr->method(); 363 argptr->method(); 364 localptr->method(); 365 }); 366 } 367 auto d15() { 368 R* ptr; 369 SmartPtr<R> sp; 370 return ([&sp](SmartPtr<R> argsp) { 371 SmartPtr<R> localsp; 372 sp->method(); 373 argsp->method(); 374 localsp->method(); 375 }); 376 } 377 auto d16() { 378 R* ptr; 379 SmartPtr<R> sp; 380 return ([&ptr](R* argptr) { 381 R* localptr; 382 take(ptr); 383 take(argptr); 384 take(localptr); 385 }); 386 } 387 auto d17() { 388 R* ptr; 389 SmartPtr<R> sp; 390 return ([&sp](SmartPtr<R> argsp) { 391 SmartPtr<R> localsp; 392 take(sp); 393 take(argsp); 394 take(localsp); 395 }); 396 } 397 #endif 398 399 void e() { 400 auto e1 = []() { 401 R* ptr; 402 SmartPtr<R> sp; 403 return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} 404 R* localptr; 405 #if __clang_major__ >= 12 406 ptr->method(); // expected-note{{implicitly captured by reference due to use here}} 407 #else 408 ptr->method(); 409 #endif 410 argptr->method(); 411 localptr->method(); 412 }); 413 }; 414 auto e2 = []() { 415 R* ptr; 416 SmartPtr<R> sp; 417 return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} 418 SmartPtr<R> localsp; 419 #if __clang_major__ >= 12 420 sp->method(); // expected-note{{implicitly captured by reference due to use here}} 421 #else 422 sp->method(); 423 #endif 424 argsp->method(); 425 localsp->method(); 426 }); 427 }; 428 auto e3 = []() { 429 R* ptr; 430 SmartPtr<R> sp; 431 return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} 432 R* localptr; 433 #if __clang_major__ >= 12 434 take(ptr); // expected-note{{implicitly captured by reference due to use here}} 435 #else 436 take(ptr); 437 #endif 438 take(argptr); 439 take(localptr); 440 }); 441 }; 442 auto e4 = []() { 443 R* ptr; 444 SmartPtr<R> sp; 445 return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} 446 SmartPtr<R> localsp; 447 #if __clang_major__ >= 12 448 take(sp); // expected-note{{implicitly captured by reference due to use here}} 449 #else 450 take(sp); 451 #endif 452 take(argsp); 453 take(localsp); 454 }); 455 }; 456 auto e5 = []() { 457 R* ptr; 458 SmartPtr<R> sp; 459 return ([=](R* argptr) { 460 R* localptr; 461 ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 462 argptr->method(); 463 localptr->method(); 464 }); 465 }; 466 auto e6 = []() { 467 R* ptr; 468 SmartPtr<R> sp; 469 return ([=](SmartPtr<R> argsp) { 470 SmartPtr<R> localsp; 471 sp->method(); 472 argsp->method(); 473 localsp->method(); 474 }); 475 }; 476 auto e8 = []() { 477 R* ptr; 478 SmartPtr<R> sp; 479 return ([=](R* argptr) { 480 R* localptr; 481 take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 482 take(argptr); 483 take(localptr); 484 }); 485 }; 486 auto e9 = []() { 487 R* ptr; 488 SmartPtr<R> sp; 489 return ([=](SmartPtr<R> argsp) { 490 SmartPtr<R> localsp; 491 take(sp); 492 take(argsp); 493 take(localsp); 494 }); 495 }; 496 auto e10 = []() { 497 R* ptr; 498 SmartPtr<R> sp; 499 return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 500 R* localptr; 501 ptr->method(); 502 argptr->method(); 503 localptr->method(); 504 }); 505 }; 506 auto e11 = []() { 507 R* ptr; 508 SmartPtr<R> sp; 509 return ([sp](SmartPtr<R> argsp) { 510 SmartPtr<R> localsp; 511 sp->method(); 512 argsp->method(); 513 localsp->method(); 514 }); 515 }; 516 auto e12 = []() { 517 R* ptr; 518 SmartPtr<R> sp; 519 return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 520 R* localptr; 521 take(ptr); 522 take(argptr); 523 take(localptr); 524 }); 525 }; 526 auto e13 = []() { 527 R* ptr; 528 SmartPtr<R> sp; 529 return ([sp](SmartPtr<R> argsp) { 530 SmartPtr<R> localsp; 531 take(sp); 532 take(argsp); 533 take(localsp); 534 }); 535 }; 536 auto e14 = []() { 537 R* ptr; 538 SmartPtr<R> sp; 539 #if __clang_major__ >= 12 540 return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} 541 R* localptr; 542 ptr->method(); 543 argptr->method(); 544 localptr->method(); 545 }); 546 #else 547 return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} 548 R* localptr; 549 ptr->method(); 550 argptr->method(); 551 localptr->method(); 552 }); 553 #endif 554 }; 555 auto e15 = []() { 556 R* ptr; 557 SmartPtr<R> sp; 558 #if __clang_major__ >= 12 559 return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} 560 SmartPtr<R> localsp; 561 sp->method(); 562 argsp->method(); 563 localsp->method(); 564 }); 565 #else 566 return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} 567 SmartPtr<R> localsp; 568 sp->method(); 569 argsp->method(); 570 localsp->method(); 571 }); 572 #endif 573 }; 574 auto e16 = []() { 575 R* ptr; 576 SmartPtr<R> sp; 577 #if __clang_major__ >= 12 578 return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} 579 R* localptr; 580 take(ptr); 581 take(argptr); 582 take(localptr); 583 }); 584 #else 585 return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} 586 R* localptr; 587 take(ptr); 588 take(argptr); 589 take(localptr); 590 }); 591 #endif 592 }; 593 auto e17 = []() { 594 R* ptr; 595 SmartPtr<R> sp; 596 #if __clang_major__ >= 12 597 return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} 598 SmartPtr<R> localsp; 599 take(sp); 600 take(argsp); 601 take(localsp); 602 }); 603 #else 604 return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} 605 SmartPtr<R> localsp; 606 take(sp); 607 take(argsp); 608 take(localsp); 609 }); 610 #endif 611 }; 612 } 613 614 void 615 R::privateMethod() { 616 SmartPtr<R> self = this; 617 std::function<void()>([&]() { 618 self->method(); 619 }); 620 std::function<void()>([&]() { 621 self->privateMethod(); 622 }); 623 std::function<void()>([&]() { 624 this->method(); 625 }); 626 std::function<void()>([&]() { 627 this->privateMethod(); 628 }); 629 std::function<void()>([=]() { 630 self->method(); 631 }); 632 std::function<void()>([=]() { 633 self->privateMethod(); 634 }); 635 std::function<void()>([=]() { 636 this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 637 }); 638 std::function<void()>([=]() { 639 this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 640 }); 641 std::function<void()>([self]() { 642 self->method(); 643 }); 644 std::function<void()>([self]() { 645 self->privateMethod(); 646 }); 647 std::function<void()>([this]() { 648 this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 649 }); 650 std::function<void()>([this]() { 651 this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 652 }); 653 std::function<void()>([this]() { 654 method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 655 }); 656 std::function<void()>([this]() { 657 privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 658 }); 659 std::function<void()>([=]() { 660 method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 661 }); 662 std::function<void()>([=]() { 663 privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} 664 }); 665 std::function<void()>([&]() { 666 method(); 667 }); 668 std::function<void()>([&]() { 669 privateMethod(); 670 }); 671 672 std::function<void()>( 673 [instance = MOZ_KnownLive(this)]() { instance->privateMethod(); }); 674 675 // It should be OK to go through `this` if we have captured a reference to it. 676 std::function<void()>([this, self]() { 677 this->method(); 678 this->privateMethod(); 679 method(); 680 privateMethod(); 681 }); 682 }