aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2002-03-17 19:09:37 -0500
committerJason Merrill <jason@gcc.gnu.org>2002-03-17 19:09:37 -0500
commit6afcef6bd2c7fc2dd55fc2684784dc582961bb37 (patch)
tree531869c61fb0a12c9731968ef268de1b009e1d6d
parent155038f242b4ebb90656547e852ad5b212b710ae (diff)
downloadgcc-6afcef6bd2c7fc2dd55fc2684784dc582961bb37.zip
gcc-6afcef6bd2c7fc2dd55fc2684784dc582961bb37.tar.gz
gcc-6afcef6bd2c7fc2dd55fc2684784dc582961bb37.tar.bz2
re PR c++/4381 (Exceptions virtually inherited from a class cause segmentation fault at run time)
PR c++/4381 * libsupc++/eh_personality.cc (get_adjusted_ptr): New static fn. (check_exception_spec): Call it. Take the thrown pointer. (__cxa_call_unexpected): Pass it. (PERSONALITY_FUNCTION): Likewise. Use get_adjusted_ptr. From-SVN: r50936
-rw-r--r--gcc/testsuite/g++.dg/eh/spec3.C24
-rw-r--r--libstdc++-v3/ChangeLog8
-rw-r--r--libstdc++-v3/libsupc++/eh_personality.cc62
3 files changed, 77 insertions, 17 deletions
diff --git a/gcc/testsuite/g++.dg/eh/spec3.C b/gcc/testsuite/g++.dg/eh/spec3.C
new file mode 100644
index 0000000..20bcfc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/spec3.C
@@ -0,0 +1,24 @@
+// PR c++/4381
+// Test that exception-specs work properly for classes with virtual bases.
+
+// { dg-do run }
+
+class Base {};
+
+struct A : virtual public Base
+{
+ A() {}
+};
+
+struct B {};
+
+void func() throw (B,A)
+{
+ throw A();
+}
+
+int main(void)
+{
+ try { func(); }
+ catch (A& a) { }
+}
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index f98da0b..718f0dc 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,11 @@
+2002-03-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/4381
+ * libsupc++/eh_personality.cc (get_adjusted_ptr): New static fn.
+ (check_exception_spec): Call it. Take the thrown pointer.
+ (__cxa_call_unexpected): Pass it.
+ (PERSONALITY_FUNCTION): Likewise. Use get_adjusted_ptr.
+
Fri Mar 15 09:55:49 2002 Anthony Green <green@redhat.com>
* configure.in: Remove useless is_mingw32.
diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc
index 9b235a0..802b9e2 100644
--- a/libstdc++-v3/libsupc++/eh_personality.cc
+++ b/libstdc++-v3/libsupc++/eh_personality.cc
@@ -96,9 +96,37 @@ get_ttype_entry (lsda_header_info *info, _Unwind_Word i)
return reinterpret_cast<const std::type_info *>(ptr);
}
+// Given the thrown type THROW_TYPE, pointer to a variable containing a
+// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
+// compare against, return whether or not there is a match and if so,
+// update *THROWN_PTR_P.
+
+static bool
+get_adjusted_ptr (const std::type_info *catch_type,
+ const std::type_info *throw_type,
+ void **thrown_ptr_p)
+{
+ void *thrown_ptr = *thrown_ptr_p;
+
+ // Pointer types need to adjust the actual pointer, not
+ // the pointer to pointer that is the exception object.
+ // This also has the effect of passing pointer types
+ // "by value" through the __cxa_begin_catch return value.
+ if (throw_type->__is_pointer_p ())
+ thrown_ptr = *(void **) thrown_ptr;
+
+ if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
+ {
+ *thrown_ptr_p = thrown_ptr;
+ return true;
+ }
+
+ return false;
+}
+
static bool
check_exception_spec (lsda_header_info *info, const std::type_info *throw_type,
- _Unwind_Sword filter_value)
+ void *thrown_ptr, _Unwind_Sword filter_value)
{
const unsigned char *e = info->TType - filter_value - 1;
@@ -106,7 +134,6 @@ check_exception_spec (lsda_header_info *info, const std::type_info *throw_type,
{
const std::type_info *catch_type;
_Unwind_Word tmp;
- void *dummy;
e = read_uleb128 (e, &tmp);
@@ -117,7 +144,12 @@ check_exception_spec (lsda_header_info *info, const std::type_info *throw_type,
// Match a ttype entry.
catch_type = get_ttype_entry (info, tmp);
- if (catch_type->__do_catch (throw_type, &dummy, 1))
+
+ // ??? There is currently no way to ask the RTTI code about the
+ // relationship between two types without reference to a specific
+ // object. There should be; then we wouldn't need to mess with
+ // thrown_ptr here.
+ if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
return true;
}
}
@@ -154,7 +186,7 @@ PERSONALITY_FUNCTION (int version,
const unsigned char *p;
_Unwind_Ptr landing_pad, ip;
int handler_switch_value;
- void *adjusted_ptr = xh + 1;
+ void *thrown_ptr = xh + 1;
// Interface version check.
if (version != 1)
@@ -294,7 +326,6 @@ PERSONALITY_FUNCTION (int version,
{
// Positive filter values are handlers.
catch_type = get_ttype_entry (&info, ar_filter);
- adjusted_ptr = xh + 1;
// Null catch type is a catch-all handler. We can catch
// foreign exceptions with this.
@@ -308,14 +339,7 @@ PERSONALITY_FUNCTION (int version,
}
else if (throw_type)
{
- // Pointer types need to adjust the actual pointer, not
- // the pointer to pointer that is the exception object.
- // This also has the effect of passing pointer types
- // "by value" through the __cxa_begin_catch return value.
- if (throw_type->__is_pointer_p ())
- adjusted_ptr = *(void **) adjusted_ptr;
-
- if (catch_type->__do_catch (throw_type, &adjusted_ptr, 1))
+ if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
{
saw_handler = true;
break;
@@ -329,7 +353,8 @@ PERSONALITY_FUNCTION (int version,
// see we can't match because there's no __cxa_exception
// object to stuff bits in for __cxa_call_unexpected to use.
if (throw_type
- && ! check_exception_spec (&info, throw_type, ar_filter))
+ && ! check_exception_spec (&info, throw_type, thrown_ptr,
+ ar_filter))
{
saw_handler = true;
break;
@@ -365,7 +390,7 @@ PERSONALITY_FUNCTION (int version,
xh->handlerSwitchValue = handler_switch_value;
xh->actionRecord = action_record;
xh->languageSpecificData = language_specific_data;
- xh->adjustedPtr = adjusted_ptr;
+ xh->adjustedPtr = thrown_ptr;
// ??? Completely unknown what this field is supposed to be for.
// ??? Need to cache TType encoding base for call_unexpected.
@@ -425,6 +450,7 @@ __cxa_call_unexpected (void *exc_obj_in)
__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.
lsda_header_info info;
@@ -433,13 +459,15 @@ __cxa_call_unexpected (void *exc_obj_in)
// If this new exception meets the exception spec, allow it.
if (check_exception_spec (&info, new_xh->exceptionType,
- xh->handlerSwitchValue))
+ new_ptr, xh->handlerSwitchValue))
__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.
#ifdef __EXCEPTIONS
const std::type_info &bad_exc = typeid (std::bad_exception);
- if (check_exception_spec (&info, &bad_exc, xh->handlerSwitchValue))
+ if (check_exception_spec (&info, &bad_exc, 0, xh->handlerSwitchValue))
throw std::bad_exception();
#endif
// Otherwise, die.