https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125213
Bug ID: 125213
Summary: [coroutines] heap-use-after-free when coroutine frame
is destroyed by the destructor of the result of
get_return_object on exception
Product: gcc
Version: 14.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: rs2740 at gmail dot com
Target Milestone: ---
I attempted to handle the new frame destruction behavior in PR125210 by having
get_return_object return a wrapper that destroys the frame on destruction if it
wasn't converted to the final return type:
#include <coroutine>
struct O {
struct return_object {
std::coroutine_handle<> h;
~return_object() { if (h) h.destroy(); }
operator O() { h = {}; return {}; }
};
struct promise_type {
std::suspend_never initial_suspend() const noexcept { return {}; }
std::suspend_never final_suspend() const noexcept { return {}; }
void unhandled_exception() { throw; }
return_object get_return_object() noexcept { return
{std::coroutine_handle<promise_type>::from_promise(*this)}; }
void return_void() {}
};
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<promise_type> h) { h.destroy(); }
decltype(auto) await_resume() const noexcept { return 1; }
};
O test() {
throw 1;
co_return;
}
int main() {
try {
test();
}
catch(...){}
}
This works with a 15.2.1 snapshot from 20260501 and 16.1.0, but produces a
heap-use-after-free with -std=c++23 -O0 -fsanitize=address on 14.3.0, 15.2.0,
and a 14.3.1 snapshot from 20260430. (On 14.2.0 it produces a double free as
expected.)