6

Why is no unhandled exception exception given by VS 2013, or any abort signal raised when the following code is executed?

#include <thread>

void f1()
{
    throw(1);
}

int main(int argc, char* argv[])
{
    std::thread(f1);
}

The C++ standard states that std::terminate should be called in the following situation:

when the exception handling mechanism cannot find a handler for a thrown exception (15.5.1)

in such cases, std::terminate() is called (15.5.2)

brettwhiteman
  • 4,210
  • 2
  • 29
  • 38
  • possible duplicate of [How can I propagate exceptions between threads?](http://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads) – user657267 Jul 19 '14 at 08:56
  • @user657267 not really. I don't want to propagate exceptions between threads, I want to know why the above code executes and terminates normally with no exceptions being raised. – brettwhiteman Jul 19 '14 at 09:00
  • 5
    You're neither joining nor detaching from that thread, so pretty sure you've got undefined behavior. (And your program probably exits before the thread has actually got a chance at running.) – Mat Jul 19 '14 at 09:03
  • @Mat thanks, I'm such an idiot. Why don't you submit that as an answer so I can mark as answer? – brettwhiteman Jul 19 '14 at 09:09
  • Well I'm not exactly sure. Seems like you should still get a `terminate` since that thread object should be live when you exit main, invoking the thread's destructor. And that calls terminate if the thread is joinable. Both clang and GCC call terminate here (Linux). – Mat Jul 19 '14 at 09:11
  • `f1` is probably never even called. You are creating an unnamed temporary thread object, and not using it. I'm pretty sure the compiler is allowed to elide its construction. At least `gcc` does just that. No thread is created. – n. m. could be an AI Jul 19 '14 at 09:12
  • @n.m. Changing it to a named thread object causes an abort signal... I guess that's the problem. – brettwhiteman Jul 19 '14 at 09:15
  • I tried and re-discovered that indeed VS is calling abort instead of terminate(); which makes it also not call any terminate handler either, which is very problematic. I read the comments afterward so didn't read Mat's suggestion initially, should I just mention you Mat or remove my answer so that you provide one? – Klaim Jul 19 '14 at 10:12
  • 18.8.3.1: "Required behavior: A terminate_handler shall terminate execution of the program without returning to the caller. Default behavior: The implementation’s default terminate_handler calls abort()." – Christophe Jul 19 '14 at 10:37

1 Answers1

3

The problem is that in this code, main() could end before the spawned thread (f1).

Try this instead:

#include <thread>

void f1()
{
    throw(1);
}

int main(int argc, char* argv[])
{
    std::thread t(f1);
    t.join(); // wait for the thread to terminate
}

This call terminate() on Coliru (gcc).

Unfortunately Visual Studio 2013 will call directly abort() instead of terminate() (in my tests at least) when encountering this so even adding a handler (using std::set_handler() ) will apparently not work. I reported this to the VS team.

Still, this code will trigger an error, while your initial code is not garanteed to.

Klaim
  • 67,274
  • 36
  • 133
  • 188
  • The call to abort would correspond to default behaviour (see 18.8.3.1. pt 3) but I confirm your test: when setting a terminate handler with set_terminate() (as defined in std, 18.8.3.2), the handler is not called. And set_unexpected() (std. D.11) is also ignorded – Christophe Jul 19 '14 at 11:09
  • @Christophe Yes the problem is that the call to abort() is done at the throw point, not in the default terminate handler nor any handler. The unexpected handler should not be called in this case because there is exception specification if I understand correctly. – Klaim Jul 19 '14 at 11:28