libco icon indicating copy to clipboard operation
libco copied to clipboard

Exceptions cannot be handled when using amd64.c or x86.c on Windows

Open CzB404 opened this issue 1 year ago • 2 comments

Hello!

When C++ code on a cothread throws an exception the stack unwinding thinks it is from a noexcept method and calls terminate instead of correctly unwinding the stack within the cothread. This seems to be a bug in how the new stack is prepared by libco in the amd64.c and x86.c backends.

Repro:

#include <stdexcept>
#include <cstdio>
#include <libco.h>

cothread_t parent;

void will_throw()
{
    throw std::runtime_error("Catch me!");
}

void entry()
{
    try
    {
        will_throw();
    }
    catch (const std::exception& e)
    {
        std::printf("%s\n", e.what());
        co_switch(parent);
    }
}

int main()
{
    parent = co_active();
    auto cothread = co_create(262144 * sizeof(void*), &entry);
    co_switch(cothread);
    return 0;
}

Edit: Correction: The statement "the stack unwinding thinks it is from a noexcept method and calls terminate" is only true when the exception is thrown from a function called by the entry function from a try block and only in the Debug configuration. If the exception is thrown directly from the try block then the exception object won't be caught properly and the executable tries to read from invalid memory.

CzB404 avatar Aug 31 '24 18:08 CzB404

This seems like something that would be nice to have for correctness. libco was extracted from a C++ codebase (higan), but that did not use exceptions (at least for anything running in a co_thread) so the issue never came up.

Unfortunately, I don't know enough about how C++ exceptions work on the various platforms that libco supports, or what makes a C++ compiler think a function is noexcept. If there's a solution that is simple and Just Works, that would be nice; if it's complex and requires different variants for every combination of architecture, OS, and C++ compiler, it might be better to just document "no exceptions in coroutines".

Screwtapello avatar Sep 01 '24 04:09 Screwtapello

Exceptions work on Linux and on Windows they work with the fiber.c backend. So it's not a case of they don't work, it's just Windows that is affected, and only the backends that use raw assembly.

CzB404 avatar Sep 01 '24 04:09 CzB404