Skip to content

C++ exceptions are not properly shared between threads #11503

@arlebedev

Description

@arlebedev

In the following minimal example:

#include <emscripten.h>
#include <thread>

extern "C" int EMSCRIPTEN_KEEPALIVE
main()
{
    std::exception_ptr error;
    std::thread t([&error](){
        try {
            throw std::runtime_error("test");
        } catch (...) {
            error = std::current_exception();
        }
    });
    t.join();

    return 0;
}
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>WASM test</title>
  <script src="wasm_sample.js"></script>
</head>
<body>
    <script>
        CreateTest();
    </script>
</body>
</html>
em++ -O0 -g -s LLD_REPORT_UNDEFINED=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0  -s MODULARIZE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_PTHREADS=1 -s EXPORT_NAME='CreateTest' -s PROXY_TO_PTHREAD=1  -std=c++1z -o main.cpp.o -c main.cpp
em++ -O0 -g -s LLD_REPORT_UNDEFINED=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MODULARIZE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_PTHREADS=1 -s EXPORT_NAME='CreateTest' -s PROXY_TO_PTHREAD=1 main.cpp.o -o wasm_sample.js

the following error occurs:

wasm_sample.js:2303 Pthread 0x722ea0 exited.
threadExit @ wasm_sample.js:2303
onmessage @ wasm_sample.worker.js:136
wasm_sample.worker.js:24 worker.js onmessage() captured an uncaught exception: TypeError: Cannot read property 'refcount' of undefined
threadPrintErr @ wasm_sample.worker.js:24
onmessage @ wasm_sample.worker.js:170
wasm_sample.worker.js:24 TypeError: Cannot read property 'refcount' of undefined
    at ___exception_decRef (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2649:19)
    at ___cxa_decrement_exception_refcount (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2663:7)
    at std::exception_ptr::~exception_ptr() (wasm-function[125]:0x2fbc)
    at __original_main (wasm-function[56]:0x113e)
    at main (wasm-function[121]:0x2f82)
    at http://127.0.0.1:8000/cpp/build/wasm_sample.js:1993:22
    at ___call_main (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2537:24)
    at __emscripten_thread_main (wasm-function[529]:0xcd88)
    at dynCall_ii (wasm-function[555]:0xd593)
    at Object.dynCall_ii (http://127.0.0.1:8000/cpp/build/wasm_sample.js:1993:22)
threadPrintErr @ wasm_sample.worker.js:24
onmessage @ wasm_sample.worker.js:171
wasm_sample.js:2438 pthread sent an error! http://127.0.0.1:8000/cpp/build/wasm_sample.worker.js:172: Uncaught TypeError: Cannot read property 'refcount' of undefined
worker.onerror @ wasm_sample.js:2438
error (async)
loadWasmModuleToWorker @ wasm_sample.js:2437
getNewWorker @ wasm_sample.js:2479
spawnThread @ wasm_sample.js:3563
_pthread_create @ wasm_sample.js:3767
proxy_main @ wasm_sample.wasm:1
(anonymous) @ wasm_sample.js:1993
callMain @ wasm_sample.js:4331
doRun @ wasm_sample.js:4374
run @ wasm_sample.js:4389
runCaller @ wasm_sample.js:4304
removeRunDependency @ wasm_sample.js:1894
receiveInstance @ wasm_sample.js:2064
receiveInstantiatedSource @ wasm_sample.js:2080
Promise.then (async)
(anonymous) @ wasm_sample.js:2103
Promise.then (async)
instantiateAsync @ wasm_sample.js:2101
createWasm @ wasm_sample.js:2128
(anonymous) @ wasm_sample.js:3880
(anonymous) @ (index):10
wasm_sample.worker.js:172 Uncaught TypeError: Cannot read property 'refcount' of undefined
    at ___exception_decRef (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2649:19)
    at ___cxa_decrement_exception_refcount (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2663:7)
    at std::exception_ptr::~exception_ptr() (wasm-function[125]:0x2fbc)
    at __original_main (wasm-function[56]:0x113e)
    at main (wasm-function[121]:0x2f82)
    at http://127.0.0.1:8000/cpp/build/wasm_sample.js:1993:22
    at ___call_main (http://127.0.0.1:8000/cpp/build/wasm_sample.js:2537:24)
    at __emscripten_thread_main (wasm-function[529]:0xcd88)
    at dynCall_ii (wasm-function[555]:0xd593)
    at Object.dynCall_ii (http://127.0.0.1:8000/cpp/build/wasm_sample.js:1993:22)
___exception_decRef @ wasm_sample.js:2649
___cxa_decrement_exception_refcount @ wasm_sample.js:2663
std::exception_ptr::~exception_ptr() @ 000a5e96:1
__original_main @ 000a5e96:1
main @ 000a5e96:1
(anonymous) @ wasm_sample.js:1993
___call_main @ wasm_sample.js:2537
__emscripten_thread_main @ 000a5e96:1
dynCall_ii @ 000a5e96:1
(anonymous) @ wasm_sample.js:1993
onmessage @ wasm_sample.worker.js:130

Seems there are exception info structures on JavaScript side which are thread-private. Similar errors occurs during any non-empty exception_ptr manipulation in threads other than the one, where the exception was created.
This bug makes it impossible to properly handle errors in real-world C++ projects. I heard that there is work in progress on a new EH mechanism but as I understand it is not yet so widely supported among all browsers so the legacy implementation also should be fixed. This is very critical for us so we are about to invest work into this issue (probably making our fork with the fix). We would like to contribute our effort into the mainline so the help from the core developers would be very appreciated, may be there are some ideas of the proper approach for the fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions