7

When an uncaught exception happens in my application, I can get the what() string of the exception by adding a global catch to my main() function, something like:

catch (std::exception& ex)
{
    std::cerr << "Error: " << ex.what() << "\n";
}

I can also get the stack trace of the location where the exception was thrown by calling backtrace() and backtrace_symbol() from inside a std::terminate() handler (set by calling std::set_terminate()). For example (ignore the memory leak):

void terminate_handler()
{
    void** buffer = new void*[15];
    int count = backtrace(buffer, 15);
    backtrace_symbols_fd(buffer, count, STDERR_FILENO);
}

…

std::set_terminate(terminate_handler);

But when I try to combine the two approaches by rethrowing the exception using throw; in my global catch, I'm getting stack trace to that catch, not to the location where the exception was originally thrown.

Is there some way I can do both (get the stack trace for the location where the exception was originally thrown and also get the value of its what()) at the same time?

svick
  • 236,525
  • 50
  • 385
  • 514
  • 2
    When you catch an exception, the stack has already been unwound, so there is not longer any trace of earlier functions. – Some programmer dude Sep 18 '13 at 15:16
  • @JoachimPileborg Right, I get that. My question is, is there some way to work around that? – svick Sep 18 '13 at 15:18
  • 3
    possible duplicate of [c++ stacktrace from the function an exception is thrown?](http://stackoverflow.com/questions/6271132/c-stacktrace-from-the-function-an-exception-is-thrown)... Or you can implement your own exception type that gets the trace in the constructor – BЈовић Sep 18 '13 at 15:34
  • @svick Unfortunately, you'd need the exception to be populated with the stack details at the point where it is thrown. It is not possible to reconstitute that information at the point where you catch it. – sbaker Sep 18 '13 at 16:56

1 Answers1

1

This should work:

void terminate_handler()
{
    void** buffer = new void*[15];
    int count = backtrace(buffer, 15);
    backtrace_symbols_fd(buffer, count, STDERR_FILENO);

    //etc.
    auto ptr = std::current_exception();
    try { std::rethrow_exception(ptr); }
    catch (std::exception & p) { std::cout << p.what() << std::endl;}
}
sbabbi
  • 11,070
  • 2
  • 29
  • 57
  • Honestly I am not even sure that this is not UB (2 exceptions active at the same time? Is `std::current_exception()` supposed to be invoked outside a `catch` clause?). I just tested this with G++ and it works. – sbabbi Sep 18 '13 at 17:12
  • `backtrace()` is already a GCC extension, so I'm not sure how does what the standard say matters. And I think that 2 active exceptions are okay. Or do you think that you can't do anything that could throw an exception in a `catch` clause? – svick Sep 18 '13 at 19:42
  • It's not like a `catch` clause, it's more like throwing-and-cathing in a destructor. Imagine `ptr` contains an exception which is not derived from `std::exception`: it won't catch it and you'll end up with 2 active exceptions (the one captured with `current_exception` and the one thrown by `rethrow_exception`). – sbabbi Sep 20 '13 at 15:29