[clang] capturing `*this` by value causes use-after-free with coroutines
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
[Example](https://gcc.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGIM6SuADJ4DJgAcj4ARpjE/gCspAAOqAqETgwe3r7%2ByanpAiFhkSwxcWaJdpgOGUIETMQEWT5%2BAVU1AnUNBEUR0bEJtvWNzTltwz2hfaUDFQCUtqhexMjsHOYAzKHI3lgA1CYbbsCMsUxExIfYJhoAgpvbu5gHR1ReDB3MtFc392ZbHyeLzcTgUBGImFYPzuvzBxC8Dj2ewAYqhUAcAOxWO5IpFMLxEPZRYioADWjAgc0x2NuuLpewhBGWDAO8QsACoCAg8AoTPEACIQLk8vb4ohUgC0Vz2YPQIBAJzCxHOJEOIME0pMWN%2B9N1ezQAH0AJ54TC0dB7ABuYi8mEONL1mP59p1uK1zpxuLF6IA7iRSaFgJTqa7dYzmayLHYqId%2BZzubyBUKE6KCahJdLZfLFWcLmrQgRNdrPY6kYaTWaLdGAHTW7x2jYOvXul0lp2hvYFq0256xvYaVRUIfDoet%2B4Y52N36wghykBvD6OARqrMK07KvNHAtXSnS4lkilUrVNpHh4gs1GoY/u6v78kMXdTmET6d3VcLz4r2fZ9cqy5bjUNmwR9sD2P1iADIxg2vNszwvNFrwnatwMgoM5jHFsYTuLsWCYUI9mg4taS9NM9ioF5%2BT2ABxbBwkfE8yJIAiuzwPYQDIykjyIx1VzQAlgTVTsBKOA4zDMPk3AYcxxKfYikUw8d%2BQ4BZaE4eJeD8DgtFIVBODcaxrBlJYVl7f4eFIAhNGUhZSRADYNmrABOLhHPs5yADZJH%2BDEuA2fROEkDSrJ0zheAUEANAsqyFjgWAkEwVRqjTMgKAgBpgAUZRDDNIQEFQH1NPMtAWCSOhzgyLKwloXL8s07TitK%2Bg4h2QxgANcF3lJUgGroWJwlYNZeB6pqAHkCRqgrgoS6pbmIDLQsCRLkDqfBNN4fhBBEMR2CkGRBEUFR1C0nQ9AMIwUAMyx9DwKJwtgZg2BAfdBFQUhLQGXDQjmBZUCSJcGHCjgJVlWNTEsax/j2CUqAUQx0gALwbfkmHQdAIQUBQof5GjwljFDA14VB3uIYg8CwO7KVIeFBDwNgABU0VoCmFgUYzVj0WVQkqnK8sm7heHBTB2Ein1lSSTgeBUtSguOkKOGwJbkr2VQAA53IlTz9TO4ACI6hhSSpCB9PBq69lwQgmM2Lg5gF6KbLshyNEkDR7KdrgMRVlWpA2RJVI4QLSDqwmFvCyLLOOmKYEQEBpuQZLyEodLMuy6recKobUBKsr/u51PauC4aBhaox2uprrC%2BIfrHo4DOs9G8a06mpbZvmmvFuqFbQgWjbhFEcRdp7g61GC3QAm1i6TZsWgbopiAHvYZ6iDej68IYb6dL%2BjJAeB2dQcuixIeh2GGARpGUbRzAMaxnHYzvRhCeJ0nyfgBZqccenGeZxZlnZrghlW3OE104WQhMLUgosmDi35lLDg6lA7BV0vLRWFxlZqw1pILWrVdZl0NsbKwptzYoKtjbKKEd7b2WrE7F2Gw3Yey9pIH2/l/Yy20ogsKEVSFaHXn7MwLDg5t3DlwhYxM0jOEkEAA%3D%3D%3D)
```c++
#include
#include
#include
struct Foo {
auto broken() {
return [*this](this auto) -> std::generator {
co_yield value;
};
}
auto working() {
return [self=*this](this auto) -> std::generator {
co_yield self.value;
};
}
int value = 0xffffffff;
};
std::function()> broken() {
return Foo{}.broken();
}
std::function()> working() {
return Foo{}.working();
}
int main () {
auto f = GEN();
for (int i : f()) {
std::cout << i << "\n";
}
}
```
When compiled with `-fsanitize=address` and `-DGEN=broken` ASAN reports a use-after-free on the `Foo` object which should've been captured by value. Note that the should-be-semantically-equivalent `working` example does not have this issue.
Contributor guide
Research direction
Start with the reduced C++ example, especially Foo::broken, the lambda capturing *this, and its std::generator return path. Reproduce with -fsanitize=address and -DGEN=broken, then compare against working. Done means the broken case no longer reports a use-after-free while the captured object remains usable by the coroutine.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100