How can a coroutine produce a dangling reference, and when does it bite?
danger takes its argument by reference and uses it after a suspension point. A later resume() reads garbage, even though the code compiles cleanly.
Task<void> danger(const std::string& s) {
co_await something();
use(s);
}
void caller() {
auto t = danger("hello");
}
Identify the bug and explain the cause.
A coroutine parameter taken by reference is not copied into the frame — only the reference is. If the referent dies before the coroutine resumes, using it is UB. It bites after the first suspension, once the caller's stack has unwound.
- ✗Assuming all coroutine parameters are deep-copied into the frame, references included
- ✗Passing a temporary to a by-reference coroutine parameter and using it after a suspend
- ✗Capturing a reference to a caller local and resuming the coroutine after the caller returns
- →Why does passing the parameter by value make the snippet safe?
- →How does this hazard interact with default arguments that are temporaries?
A dangling reference in the frame
Task<void> danger(const std::string& s) { // s is a reference — NOT copied into the frame
co_await something(); // the caller's stack has already unwound
use(s); // ❌ UB: the referent is destroyed
}
void caller() {
auto t = danger("hello"); // a temporary std::string is created here...
} // ...and destroyed at the end of the full expression
// the coroutine is suspended; the temporary is dead; a later resume() is UB
The coroutine frame stores local variables, but a reference parameter stores only the reference. The temporary std::string lives until the end of the danger(...) call's full expression. As soon as the coroutine suspends on co_await, that temporary is destroyed. Any resume() afterwards reads a dead object.
Safe: by value
Task<void> safe(std::string s) { // s is COPIED into the frame
co_await something();
use(s); // ✅ OK: the copy lives in the frame
}
Passing by value places an owned copy in the frame; its lifetime matches the frame's. The rule: take coroutine parameters by value unless you can prove the referent outlives the whole frame.