diff options
Diffstat (limited to 'libstdc++-v3/libsupc++/eh_personality.cc')
-rw-r--r-- | libstdc++-v3/libsupc++/eh_personality.cc | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index acc9c2eb63e..2b315c3956e 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -1,5 +1,5 @@ // -*- C++ -*- The GNU C++ exception personality routine. -// Copyright (C) 2001 Free Software Foundation, Inc. +// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. // // This file is part of GNU CC. // @@ -124,6 +124,8 @@ get_adjusted_ptr (const std::type_info *catch_type, return false; } +// Return true if THROW_TYPE matches one if the filter types. + static bool check_exception_spec (lsda_header_info *info, const std::type_info *throw_type, void *thrown_ptr, _Unwind_Sword filter_value) @@ -154,6 +156,18 @@ check_exception_spec (lsda_header_info *info, const std::type_info *throw_type, } } +// Return true if the filter spec is empty, ie throw(). + +static bool +empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) +{ + const unsigned char *e = info->TType - filter_value - 1; + _Unwind_Word tmp; + + e = read_uleb128 (e, &tmp); + return tmp == 0; +} + // Using a different personality function name causes link failures // when trying to mix code using different exception handling models. #ifdef _GLIBCPP_SJLJ_EXCEPTIONS @@ -197,6 +211,7 @@ PERSONALITY_FUNCTION (int version, && exception_class == __gxx_exception_class) { handler_switch_value = xh->handlerSwitchValue; + language_specific_data = xh->languageSpecificData; landing_pad = (_Unwind_Ptr) xh->catchTemp; found_type = (landing_pad == 0 ? found_terminate : found_handler); goto install_context; @@ -275,7 +290,7 @@ PERSONALITY_FUNCTION (int version, // If ip is not present in the table, call terminate. This is for // a destructor inside a cleanup, or a library routine the compiler // was not expecting to throw. - found_type = (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate); + found_type = found_terminate; goto do_something; found_something: @@ -327,23 +342,15 @@ PERSONALITY_FUNCTION (int version, // Positive filter values are handlers. catch_type = get_ttype_entry (&info, ar_filter); - // Null catch type is a catch-all handler. We can catch - // foreign exceptions with this. - if (! catch_type) - { - if (!(actions & _UA_FORCE_UNWIND)) - { - saw_handler = true; - break; - } - } - else if (throw_type) + // Null catch type is a catch-all handler; we can catch foreign + // exceptions with this. Otherwise we must match types. + if (! catch_type + || (throw_type + && get_adjusted_ptr (catch_type, throw_type, + &thrown_ptr))) { - if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr)) - { - saw_handler = true; - break; - } + saw_handler = true; + break; } } else @@ -352,9 +359,12 @@ PERSONALITY_FUNCTION (int version, // ??? How do foreign exceptions fit in? As far as I can // see we can't match because there's no __cxa_exception // object to stuff bits in for __cxa_call_unexpected to use. + // Allow them iff the exception spec is non-empty. I.e. + // a throw() specification results in __unexpected. if (throw_type - && ! check_exception_spec (&info, throw_type, thrown_ptr, - ar_filter)) + ? ! check_exception_spec (&info, throw_type, thrown_ptr, + ar_filter) + : empty_exception_spec (&info, ar_filter)) { saw_handler = true; break; @@ -400,19 +410,37 @@ PERSONALITY_FUNCTION (int version, } install_context: - if (found_type == found_terminate) + // We can't use any of the cxa routines with foreign exceptions, + // because they all expect ue_header to be a struct __cxa_exception. + // So in that case, call terminate or unexpected directly. + if ((actions & _UA_FORCE_UNWIND) + || exception_class != __gxx_exception_class) { - __cxa_begin_catch (&xh->unwindHeader); - __terminate (xh->terminateHandler); + if (found_type == found_terminate) + std::terminate (); + else if (handler_switch_value < 0) + { + try + { std::unexpected (); } + catch(...) + { std::terminate (); } + } } - - // Cache the TType base value for __cxa_call_unexpected, as we won't - // have an _Unwind_Context then. - if (handler_switch_value < 0) + else { - parse_lsda_header (context, xh->languageSpecificData, &info); - xh->catchTemp = base_of_encoded_value (info.ttype_encoding, - context); + if (found_type == found_terminate) + { + __cxa_begin_catch (&xh->unwindHeader); + __terminate (xh->terminateHandler); + } + + // Cache the TType base value for __cxa_call_unexpected, as we won't + // have an _Unwind_Context then. + if (handler_switch_value < 0) + { + parse_lsda_header (context, language_specific_data, &info); + xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); + } } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), @@ -457,20 +485,19 @@ __cxa_call_unexpected (void *exc_obj_in) catch(...) { // Get the exception thrown from unexpected. - // ??? Foreign exceptions can't be stacked this way. - + __cxa_eh_globals *globals = __cxa_get_globals_fast (); __cxa_exception *new_xh = globals->caughtExceptions; void *new_ptr = new_xh + 1; - + // We don't quite have enough stuff cached; re-parse the LSDA. 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_switch_value)) __throw_exception_again; - + // If the exception spec allows std::bad_exception, throw that. // We don't have a thrown object to compare against, but since // bad_exception doesn't have virtual bases, that's OK; just pass 0. @@ -479,6 +506,7 @@ __cxa_call_unexpected (void *exc_obj_in) if (check_exception_spec (&info, &bad_exc, 0, xh_switch_value)) throw std::bad_exception(); #endif + // Otherwise, die. __terminate (xh_terminate_handler); } |