Catching unwanted exception at throw site

Hi

Not sure if this is quite the right place - but maybe somebody here can point me to the right place.

Problem: C++ code throws exception at a point in time where it should really not be throwing an exception. To catch this, I have a lambda declared noexcept.

What I want to happen: the debugger stops, and points me at the line of code that is executing “throw FooException();”

What actually happens: I end up with the stack looking like
(lldb) bt

  • thread #1, name = ‘soffice.bin’, stop reason = signal SIGABRT
    frame #0: libc.so.6__GI___pthread_kill at pthread_kill.c:44:76 frame #1: libc.so.6__GI___pthread_kill [inlined] __pthread_kill_internal(signo=6, threadid=) at pthread_kill.c:78:10
    frame #2: libc.so.6`__GI___pthread_kill(threadid=, signo=6) at pthread_kill.c:89:10
    • frame #3: libc.so.6__GI_raise(sig=6) at raise.c:26:13 frame #4: libc.so.6__GI_abort at abort.c:79:7
      frame #5: libstdc++.so.6___lldb_unnamed_symbol7244 + 96 frame #6: libstdc++.so.6___lldb_unnamed_symbol7656 + 12
      frame #7: libstdc++.so.6std::terminate() + 23 frame #8: libvcllo.so__clang_call_terminate + 14
      frame #9: libvcllo.so`SalUserEventList::DispatchUserEvents(bool)::$_0::operator()(this=0x00007fffffff3db0) const at salusereventlist.cxx:119:58

This is intrinsic to how the Itanium C++ ABI works: it unwinds the stack until it reaches a catch. The noexcept function is inserting a catch (catchall) that then branches to std::terminate to prevent exceptions from propagating. By the time you land in the lambda, you have already destroyed the stack and so can’t see where it came from. The best thing to do in a debugger is stick a breakpoint on __cxa_throw and script it to print a backtrace and then continue. This will give you a backtrace everywhere that an exception is thrown and the last place you see one before hitting this terminate will be the right one.

Thanks David for that explanation.

Presumably the Itanium ABI is implemented as part of some runtime? Perhaps it could be tweaked to do something different in debug mode? I would imagine that the stack unwinding is non-destructive, so making the stack appear to be coming from a different point should not be that hard?

This is a pain point for any codebase that uses exceptions - what I am trying to do here is not to fix a specific bug, but to make a class of bugs easier to deal with.

Try setting an exception breakpoint with “breakpoint set -E c++”.

Presumably the Itanium ABI is implemented as part of some runtime? Perhaps it could be tweaked to do something different in debug mode? I would imagine that the stack unwinding is non-destructive, so making the stack appear to be coming from a different point should not be that hard?

It’s actually two libraries. There is a generic unwinder, which handles the stack unwinding, and then there is the C++ runtime that sits atop this and implements language-specific behaviour. When you throw an object, the compiler emits calls to two C++ runtime functions. The first allocates space for the object, the second (__cxa_throw, where I suggested you put the breakpoint) throws the exception. It does this by invoking the generic unwinder.

The generic unwinder does two phases. First, it walks the stack to find a catch. If there is no catch, there is a place where you can handle it, but if there is a catch (or anything catch-like that blocks propagation), then the generic unwinder will do a second phase and run cleanups in each function between the throw and the catch. Each iteration of that destroys the top of the stack. Once it reaches the catch site, control is transferred into the program. The stack is gone at this point.

You can make the runtime capture the stack on exception throw fairly easily (though that is slow). There’s also a C++ standards proposal (hopefully picked up soon, the original author sadly died a few weeks ago) that will allow automatic stack capture in certain cases to aid debugging.

Thanks David. That is useful.

If there is no catch, there is a place where you can handle it

What does this ^^^^ piece mean?
That sounds like if I dont declare a catch block I could maybe do something special?

The noexcept thing (in a function that calls non-noexcept things), I believe, is inserting something equivalent to a catch that calls terminate. This means that the stack is unwound to get there, and then it dies.