aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/libsupc++/eh_personality.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/libsupc++/eh_personality.cc')
-rw-r--r--libstdc++-v3/libsupc++/eh_personality.cc98
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);
}