-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RuntimeError: unreachable
with std::thread
in a library
#15892
Comments
Interestingly enough, if I compile as a native program with g++, using this "driver" program: #include<iostream>
extern "C" void async_do_work();
int main(int argc, char *argv[]) {
async_do_work();
return 0;
} ...that also dies with an error message: "terminate called without an active exception", followed by a core dump. But using join or detach and things are OK for both native and emscripten: // lib.cc
#include <iostream>
#include <thread>
#include <unistd.h>
extern "C" void async_do_work() {
std::cerr << "do work" << std::endl;
std::thread t([&] {
std::cerr << "in thread" << std::endl;
// do nothing
});
//t.join();
t.detach();
sleep(1);
std::cerr << "after" << std::endl;
return;
}
|
Is it undefined behaviour perhaps to return from the function while the thread is still alive? i.e. won't it result in a use after free if you return from async_do_work without joining? (I think even detaching might be enough?) Do you still think this is a bug or can it be closed? |
Actually yes, it looks like either From https://en.cppreference.com/w/cpp/thread/thread:
|
It's a call to |
I seem like the issue is some kind of use-after-free (the running thread thinks the std::thread object is still around but in fact it has been destroyed due to return from the function), which is UB, and so I don't think there is necessarily anything we can or should do differently here, is there? We could investigate how control flow finally led to that unreachable, but I'm not that would lead us anywhere useful, since the code is likely accessing invalid memory/free'd memory locations. |
I don't think it's actually a use-after-free? It's fine to return from a thread before joining or detaching it. int main() {
std::thread t([&] {
printf("thread reached\n");
});
sleep(1);
t.join();
} is definitely well-defined C++. There is a bug in the program, which is that it's calling the destructor before calling Anyway, I agree it's probably not very important, since the program is definitely bugged. But I don't think it's UB. |
Ah.. thank for pointing that out. I didn't see that documentation you liked to. Assuming this is a bug in emscripten then I agree we should fix it. If the bug exists in upstream libc++ then we should open a bug there. |
(BTW I didn't mean to ever say that returning from a thread entry point was the issue.. I was only ever referring to the calling of the destructor for the thread object which was caused by returning from the function in which it was defined) |
It looks like
Without -g I see the same thing you do:
I will take a look at why |
Looks like this is expected behaviour right now: emscripten/system/lib/libcxxabi/src/abort_message.cpp Lines 36 to 50 in 9127157
We don't currently have a debug flavor of libc++ so this always ends up calling |
@kripken do you think it worth building a |
Use `abort()` rather than `__builtin_trap()` here so that the use will see `Aborted(native code called abort())` rather than just `RuntimeError: unreachable`. We could also consider building a `-debug` flavor of libc++ but I think this is still a worthwhile change. See #15892
Hmm, a debug variation of a such a large library has downsides. But if it would help debugging issues like this, how about splitting out a tiny library that does have |
libc++ is actually a very tiny library... its almost all defined in headers. |
Hmm, it is one of the slowest to build though... Takes 9 seconds on my laptop. Only thing slower is libc. |
Interesting, you are right.. there must be some sources there that are pathologically slow to compile. For now I think #15902 is enough. |
Use `abort()` rather than `__builtin_trap()` here so that the use will see `Aborted(native code called abort())` rather than just `RuntimeError: unreachable`. We could also consider building a `-debug` flavor of libc++ but I think this is still a worthwhile change. See #15892
I'm going to close this on the assumption that #15902 has changed the error from "unreachable" to "abort", which is good enough for me. (I can't test myself, unfortunately.) |
This is with emcc version
(I encountered this while worrying about #15868, but it's apparently unrelated.)
Here's a C++ file:
Build with
and trying to use it from Javascript:
results in
It evidently is not unreachable.
Note that this doesn't happen if
t
is leaked - presumably there's something in thestd::thread
destructor which is problematic.The text was updated successfully, but these errors were encountered: