diff options
-rw-r--r-- | gcc/testsuite/g++.dg/eh/unexpected1.C | 46 | ||||
-rw-r--r-- | libstdc++-v3/ChangeLog | 6 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_personality.cc | 21 |
3 files changed, 67 insertions, 6 deletions
diff --git a/gcc/testsuite/g++.dg/eh/unexpected1.C b/gcc/testsuite/g++.dg/eh/unexpected1.C new file mode 100644 index 0000000..26a5848 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/unexpected1.C @@ -0,0 +1,46 @@ +// PR 3719 +// Test that an unexpected handler can rethrow to categorize. +// { dg-do run } + +#include <exception> + +extern "C" void abort (); + +struct One { }; +struct Two { }; + +static void +handle_unexpected () +{ + try + { + throw; + } + catch (One &) + { + throw Two (); + } +} + +static void +doit () throw (Two) +{ + throw One (); +} + +main () +{ + std::set_unexpected (handle_unexpected); + + try + { + doit (); + } + catch (Two &) + { + } + catch (...) + { + abort (); + } +} diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f280238..948d4d5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2002-03-30 Richard Henderson <rth@redhat.com> + + PR c++/3719 + * libsupc++/eh_personality.cc (__cxa_call_unexpected): Copy handler + data out of the exception struct before calling unexpectedHandler. + 2002-03-27 Roger Sayle <roger@eyesopen.com> * include/c_std/std_cmath.h: To prevent problems overloading diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index 802b9e2..35e93a3 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -439,7 +439,18 @@ __cxa_call_unexpected (void *exc_obj_in) ~end_catch_protect() { __cxa_end_catch(); } } end_catch_protect_obj; + lsda_header_info info; __cxa_exception *xh = __get_exception_header_from_ue (exc_obj); + const unsigned char *xh_lsda; + _Unwind_Sword xh_switch_value; + std::terminate_handler xh_terminate_handler; + + // If the unexpectedHandler rethrows the exception (e.g. to categorize it), + // it will clobber data about the current handler. So copy the data out now. + xh_lsda = xh->languageSpecificData; + xh_switch_value = xh->handlerSwitchValue; + xh_terminate_handler = xh->terminateHandler; + info.ttype_base = (_Unwind_Ptr) xh->catchTemp; try { __unexpected (xh->unexpectedHandler); } @@ -453,13 +464,11 @@ __cxa_call_unexpected (void *exc_obj_in) void *new_ptr = new_xh + 1; // We don't quite have enough stuff cached; re-parse the LSDA. - lsda_header_info info; - parse_lsda_header (0, xh->languageSpecificData, &info); - info.ttype_base = (_Unwind_Ptr) xh->catchTemp; + parse_lsda_header (0, xh_lsda, &info); // If this new exception meets the exception spec, allow it. if (check_exception_spec (&info, new_xh->exceptionType, - new_ptr, xh->handlerSwitchValue)) + new_ptr, xh_switch_value)) __throw_exception_again; // If the exception spec allows std::bad_exception, throw that. @@ -467,10 +476,10 @@ __cxa_call_unexpected (void *exc_obj_in) // bad_exception doesn't have virtual bases, that's OK; just pass 0. #ifdef __EXCEPTIONS const std::type_info &bad_exc = typeid (std::bad_exception); - if (check_exception_spec (&info, &bad_exc, 0, xh->handlerSwitchValue)) + if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value)) throw std::bad_exception(); #endif // Otherwise, die. - __terminate(xh->terminateHandler); + __terminate (xh_terminate_handler); } } |