[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 Jonathan Wakely changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution|--- |FIXED Target Milestone|--- |8.0 --- Comment #17 from Jonathan Wakely --- Fixed for GCC 8.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #16 from Jonathan Wakely --- Author: redi Date: Mon Jun 12 16:37:28 2017 New Revision: 249130 URL: https://gcc.gnu.org/viewcvs?rev=249130&root=gcc&view=rev Log: PR libstdc++/55917 do not handle exceptions in std::thread PR libstdc++/55917 * src/c++11/thread.cc (execute_native_thread_routine): Remove try-block so that exceptions propagate out of the thread and terminate is called by the exception-handling runtime. (execute_native_thread_routine_compat): Likewise. * testsuite/30_threads/thread/cons/terminate.cc: New. Added: trunk/libstdc++-v3/testsuite/30_threads/thread/cons/terminate.cc Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/src/c++11/thread.cc
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #15 from Howard Hinnant --- To help clarify my proposal, here is a patch: diff --git a/libstdc++-v3/src/c++11/thread.cc b/libstdc++-v3/src/c++11/thread.cc index 906cafa..cfca178 100644 --- a/libstdc++-v3/src/c++11/thread.cc +++ b/libstdc++-v3/src/c++11/thread.cc @@ -79,19 +79,7 @@ namespace std _GLIBCXX_VISIBILITY(default) thread::__shared_base_type __local; __local.swap(__t->_M_this_ptr); - __try - { - __t->_M_run(); - } - __catch(const __cxxabiv1::__forced_unwind&) - { - __throw_exception_again; - } - __catch(...) - { - std::terminate(); - } - + __t->_M_run(); return nullptr; } } My colleague Miguel Portilla has tested this patch with the following code: #include #include void a(int i); void b(int i); void c(int i); int main() { auto t = std::thread{a, 3}; t.join(); } void a(int i) { b(i-1); } void b(int i) { c(i-1); } void c(int i) { throw std::runtime_error("A good message"); } And the stack dump looks like: Thread 2 (Thread 0x7f090b47c740 (LWP 1865)): #0 0x7f090b0688ed in pthread_join (threadid=139676803389184, thread_return=0x0) at pthread_join.c:90 #1 0x7f090ad9c767 in __gthread_join (__value_ptr=0x0, __threadid=) at /home/mickey/gcc-5.4.0/build/x86_64-linux-gnu/libstdc++-v3/include/x86_64-linux-gnu/bits/gthr-default.h:668 #2 std::thread::join (this=0x7ffd1dae6430) at ../../../../../libstdc++-v3/src/c++11/thread.cc:96 #3 0x00400f39 in main () Thread 1 (Thread 0x7f090a3fd700 (LWP 1866)): #0 0x7f090a433267 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55 #1 0x7f090a434eca in __GI_abort () at abort.c:89 #2 0x7f090ad747dd in __gnu_cxx::__verbose_terminate_handler () at ../../../../libstdc++-v3/libsupc++/vterminate.cc:95 #3 0x7f090ad72866 in __cxxabiv1::__terminate (handler=) at ../../../../libstdc++-v3/libsupc++/eh_terminate.cc:47 #4 0x7f090ad728b1 in std::terminate () at ../../../../libstdc++-v3/libsupc++/eh_terminate.cc:57 #5 0x7f090ad72ac8 in __cxxabiv1::__cxa_throw (obj=0x7f0904000940, tinfo=0x604360 , dest=0x400ce0 ) at ../../../../libstdc++-v3/libsupc++/eh_throw.cc:87 #6 0x00400fdd in c(int) () #7 0x00400fa0 in b(int) () #8 0x00400f85 in a(int) () #9 0x00402574 in void std::_Bind_simple::_M_invoke<0ul>(std::_Index_tuple<0ul>) () #10 0x00402493 in std::_Bind_simple::operator()() () #11 0x00402432 in std::thread::_Impl >::_M_run() () #12 0x7f090ad9c820 in std::execute_native_thread_routine (__p=) at ../../../../../libstdc++-v3/src/c++11/thread.cc:82 #13 0x7f090b0676aa in start_thread (arg=0x7f090a3fd700) at pthread_create.c:333 #14 0x7f090a504e9d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 Howard Hinnant changed: What|Removed |Added CC||howard.hinnant at gmail dot com --- Comment #14 from Howard Hinnant --- The main function is not wrapped in a try / catch and an unhandled exception on the main thread still calls std::terminate() as required. I believe that gcc already correctly implements the call to std::terminate() for threads elsewhere, and with the same code that it does for main. It is in the function __cxa_throw, implemented by libsupc++. Here is the specification: http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-throw which says in part: > __Unwind_RaiseException begins the process of stack unwinding, described in > Section 2.5. In special cases, such as an inability to find a handler, > _Unwind_RaiseException may return. In that case, __cxa_throw will call > terminate, assuming that there was no handler for the exception. And here is where it is implemented: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_throw.cc#L87 As long as libsupc++ is being used on the platform, I think you are good to remove the try/catch from execute_native_thread_routine. Fwiw, this is what is done on libc++ / libc++abi (no try/catch at the top of std::thread, and let __cxa_throw call terminate). We get beautiful stack dumps from threaded code over there. :-)
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 Roger Orr changed: What|Removed |Added CC||rogero at howzatt dot demon.co.uk --- Comment #13 from Roger Orr --- I am also affected by this problem. What is the status of the idea Jonathan made (2013-07-02 11:26:53 UTC): ... and I think we can make a change for targets where we know the behaviour is OK ...
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #12 from Jonathan Wakely --- Yes it will probably work on all platforms using the Itanium exception-handling ABI, unless the OS's pthread_create (or equiv) has explicit exception-handling.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #11 from Yuri Aksenov --- > Where is that guaranteed? Where is it implemented? And here is stack trace of patched version, it seems to be implemented in __cxxabiv1::__cxa_throw (gdb) bt #0 0x7703ad25 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x7703c1a8 in __GI_abort () at abort.c:91 #2 0x7791d68d in __gnu_cxx::__verbose_terminate_handler () at ../../../../libstdc++-v3/libsupc++/vterminate.cc:95 #3 0x7791b796 in __cxxabiv1::__terminate (handler=) at ../../../../libstdc++-v3/libsupc++/eh_terminate.cc:40 #4 0x7791b7c3 in std::terminate () at ../../../../libstdc++-v3/libsupc++/eh_terminate.cc:50 #5 0x7791b9ee in __cxxabiv1::__cxa_throw (obj=0x7940, tinfo=, dest=) at ../../../../libstdc++-v3/libsupc++/eh_throw.cc:83 #6 0x004010f2 in f () at main.cpp:5 #7 0x0040242d in std::_Bind_simple::_M_invoke<>(std::_Index_tuple<>) (this=0x606040) at /usr/include/c++/4.7/functional:1598 #8 0x0040237d in std::_Bind_simple::operator()() (this=0x606040) at /usr/include/c++/4.7/functional:1586 #9 0x00402316 in std::thread::_Impl >::_M_run() (this=0x606028) at /usr/include/c++/4.7/thread:115 #10 0x0040266d in std::(anonymous namespace)::execute_native_thread_routine (__p=0x606028) at thread.cpp:73 #11 0x77bc6e0e in start_thread (arg=0x77005700) at pthread_create.c:305 #12 0x770ea2cd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #10 from Yuri Aksenov --- OK, [thread.thread.constr]/4 says: > If the invocation of INVOKE(decay_copy( std::forward(f)), > decay_copy(std::forward(args))...) terminates with an uncaught > exception, > std::terminate shall be called. And [except.handle]/9 says: > If no matching handler is found, the function std::terminate() is called So we don't need to set default handler unless there is bug in implementation of [except.handle]/9 I have tested std::thread with removed catch(...) for both -m32 and -m64 environments on gcc version 4.7.1 20120723 [gcc-4_7-branch revision 189773] (SUSE Linux) Target: x86_64-suse-linux And I can test it on Target: armv5b-softfloat-linux But I can not be shure for any possible target
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #9 from Jonathan Wakely --- P.S. I do want to improve the behaviour, and I think we can make a change for targets where we know the behaviour is OK, but we need to check carefully that it works correctly, not just remove the catch(...)
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #8 from Jonathan Wakely --- (In reply to Yuri Aksenov from comment #7) > > If it's guaranteed that an uncaught exception leaving that function will > > still > > call terminate, then the catch(...) block could be removed. Maybe I could > > do > > that conditionally for targets where it's known to work as required. > > I vote for this enhancement to remove catch(...) block from > execute_native_thread_routine function. This isn't a democracy ;) > According to standard (15.3) Handling an exception > > If no matching handler is found, the function std::terminate() is called; > > whether or not the stack is unwound before this call to std::terminate() is > > implementation-defined (15.5.1). > > So if we remove catch(...), std::terminate should be called anyway (it's a > bug otherwise). The catch(...) is there to provide the [thread.thread.constr]/4 requirement that std::terminate is called. If it isn't there, are you saying Pthreads or the OS guarantees that an exception in the function passed to pthread_create() will cause a call to std::terminate()? Where is that guaranteed? Where is it implemented? You can't just say "rely on the implementation, it's a bug otherwise", this code **is** the implementation.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 Yuri Aksenov changed: What|Removed |Added CC||yuri.aksenov at gmail dot com --- Comment #7 from Yuri Aksenov --- > If it's guaranteed that an uncaught exception leaving that function will > still > call terminate, then the catch(...) block could be removed. Maybe I could do > that conditionally for targets where it's known to work as required. I vote for this enhancement to remove catch(...) block from execute_native_thread_routine function. According to standard (15.3) Handling an exception > If no matching handler is found, the function std::terminate() is called; > whether or not the stack is unwound before this call to std::terminate() is > implementation-defined (15.5.1). So if we remove catch(...), std::terminate should be called anyway (it's a bug otherwise). But GCC implementaion will leave stack unwound making it easier to debug.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #6 from Jonathan Wakely 2013-01-09 14:42:00 UTC --- (In reply to comment #5) > Yes, I thought two reports were in order, as they are only vaguely related. > To > me, this one is the most important problem. I struggle to understand how I > can > be the first to have this problem. Surely it must be an enormous problem if > you use std::thread? I'm working on a somewhat large multi-threaded program, > and if there's an exception anywhere, e.g. a failed range-check in a > container, > it's *completely impossible* to find the problem in a debugger. If you're running in the debugger, rather than examining a core file post-mortem, you can use "catch throw" or "break __cxa_throw" to break when the exception is thrown. Otherwise you already know the workaround, put 'noexcept' on the function you pass to std::thread (which breaks pthread_cancel but if you're not using that it doesn't matter.) > We've now > switched to boost::thread instead because it does not have this problem. > > I must say that I'm very surprised that you call it an enhancement, The current implementation conforms to the standard. > and that > you consider closing it as WONTFIX, I've explained why it can't easily be changed, unless anyone has some idea I haven't thought of yet to preserve pthread_cancel behaviour and preserve the requirement that std::terminate() is called. > seeing how the current behavior is so > mindbogglingly unfriendly. There is a reason why GCC does not unwind the > stack > for non-threaded unhandled exceptions. The behaviour comes directly from the explicit requirement in the standard that an unhandled exception in a std::thread must call std::terminate. If it's guaranteed that an uncaught exception leaving that function will still call terminate, then the catch(...) block could be removed. Maybe I could do that conditionally for targets where it's known to work as required.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #5 from Tobias Ringström 2013-01-09 14:06:08 UTC --- Yes, I thought two reports were in order, as they are only vaguely related. To me, this one is the most important problem. I struggle to understand how I can be the first to have this problem. Surely it must be an enormous problem if you use std::thread? I'm working on a somewhat large multi-threaded program, and if there's an exception anywhere, e.g. a failed range-check in a container, it's *completely impossible* to find the problem in a debugger. We've now switched to boost::thread instead because it does not have this problem. I must say that I'm very surprised that you call it an enhancement, and that you consider closing it as WONTFIX, seeing how the current behavior is so mindbogglingly unfriendly. There is a reason why GCC does not unwind the stack for non-threaded unhandled exceptions. Perhaps std::thread is not widely used yet, or I'm the only one with buggy code?
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #4 from Jonathan Wakely 2013-01-09 13:59:58 UTC --- One option would be to make the start function have a dynamic-exception-specification of throw(__cxxabiv1::__forced_unwind), which would allow the cancellation exception to propagate (as required) but prevent any other exceptions, but that would result in a call to std::unexpected() rather than std::terminate(), and a user could have replaced the unexpected_handler, so we would not be able to meet the requirement that std::terminate() is called. On top of that, I think the stack would still get unwound before the call to std:unexpected, and dynamic-exception-specifications and unexpected handlers are deprecated in C++11. So I don't think we want to do that. My inclination is to close this as WONTFIX.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #3 from Jonathan Wakely 2013-01-09 13:48:04 UTC --- Ah, I se PR 55918 - thanks!
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 Jonathan Wakely changed: What|Removed |Added Severity|normal |enhancement --- Comment #2 from Jonathan Wakely 2013-01-09 13:44:35 UTC --- As I said at http://gcc.gnu.org/ml/gcc-help/2013-01/msg00068.html this can't be changed for std::thread, see http://gcc.gnu.org/ml/libstdc++/2012-12/msg00062.html and the patch at http://gcc.gnu.org/ml/libstdc++/2012-12/msg00068.html for discussion and code that absolutely requires exceptions of type __forced_unwind to be able to escape the thread start function, otherwise thread cancellation crashes the program, which is not acceptable. If the function is not noexcept then it must catch exceptions to ensure std::terminate is called as required, and catching the exception causes the stack to be unwound. So it's difficult do anything about std::thread. Please open a separate bug (with Component=c++) for the http://gcc.gnu.org/ml/gcc-help/2013-01/msg00058.html issue when noexcept interacts with a destructor on the stack. That applies to code not using std::thread too.
[Bug libstdc++/55917] Impossible to find/debug unhandled exceptions in an std::thread
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917 --- Comment #1 from Tobias Ringström 2013-01-09 13:22:52 UTC --- Created attachment 29120 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=29120 Test program to illustrate the problem