llvm / llvm/llvm-project

[clang] capturing `*this` by value causes use-after-free with coroutines

Open
#208,938 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.