https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55918

Sergey Barannikov <barannikov88 at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |barannikov88 at gmail dot com

--- Comment #4 from Sergey Barannikov <barannikov88 at gmail dot com> ---
This is the ABI problem. The search phase of the unwinding process cannot
distinguish between a case when a true handler found and a case when the search
process should stop, because it has reached a call site that must not pass the
exception through. In both cases _URC_HANDLER_FOUND is returned by the
personality routine, and the second phase of the unwinding process begins (the
actual unwinding).

There is another problem in LSDA format (in action table format to be precise).
Consider the following example:

void bad_guy() noexcept {
  try {
    Foo foo;
    throw 0;
  } catch (float) {
    // Don't catch int.
  }
}

void level1() {
  bad_guy();
  throw "dead code";
}

int main() {
  try {
    level1();
  } catch (const char *) {
  }
}

When you compile and run it you get:

Foo::Foo()
terminate called after throwing an instance of 'int'
Aborted (core dumped)


It works as expected. But (the funny thing) if you change "catch (const char
*)" in main to "catch (int)", you will get this:

Foo::Foo()
Foo::~Foo()
terminate called without an active exception
Aborted (core dumped)

This is because there is currently no way to represent a "Terminate" action in
the action table of LSDA. gcc represents it as a simply cleanup action, that
means that the unwinder does not stop at a noexcept function and continues
searching for a handler up the stack.
In the original example there is no handler for the exception thrown, and the
runtime terminates the program instantly (no stack unwinding done). When one
changes "catch (const char *)" to "catch (int)", the unwinder finds this
handler at the search phase and launches the second, unwinding, phase. The
unwinding process then destroys the local object "foo", checks the exception
type for matching "float", and falls into the code that calls std::terminate
when the matching fails. Since there is no __cxa_begin_catch prior to
std::terminate, we get the error message "terminate called without an active
exception" instead of correct "terminate called after throwing an instance of
'int'".

Reply via email to