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.)

Reply via email to