diff --git a/eh_personality.c b/eh_personality.c index b74ad76..eaf0060 100644 --- a/eh_personality.c +++ b/eh_personality.c @@ -503,11 +503,17 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0) if (0 == ex->cxx_exception) { ex->cxx_exception = objc_init_cxx_exception(ex->object); - ex->cxx_exception->private_1 = exceptionObject->private_1; - ex->cxx_exception->private_2 = exceptionObject->private_2; } + // We now have two copies of the _Unwind_Exception object (which stores + // state for the unwinder) in flight. Make sure that they're in sync. + ex->cxx_exception->private_1 = exceptionObject->private_1; + ex->cxx_exception->private_2 = exceptionObject->private_2; exceptionObject = ex->cxx_exception; exceptionClass = cxx_exception_class; + int ret = CALL_PERSONALITY_FUNCTION(__gxx_personality_v0); + exceptionObject->private_1 = ex->cxx_exception->private_1; + exceptionObject->private_2 = ex->cxx_exception->private_2; + return ret; } return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0); } @@ -588,8 +594,7 @@ id objc_begin_catch(struct _Unwind_Exception *exceptionObject) { DEBUG_LOG("c++ catch\n"); td->current_exception_type = CXX; - id *obj = __cxa_begin_catch(exceptionObject); - return obj ? *obj : nil; + return __cxa_begin_catch(exceptionObject); } DEBUG_LOG("foreign exception catch\n"); // Box if we have a boxing function. diff --git a/objcxx_eh.cc b/objcxx_eh.cc index 25466ab..a60c8ce 100644 --- a/objcxx_eh.cc +++ b/objcxx_eh.cc @@ -75,9 +75,12 @@ typedef void (*terminate_handler)(); namespace std { /** - * std::type_info defined with the GCC ABI. This may not be exposed in - * public headers, but is required for correctly implementing the unified - * exception model. + * std::type_info, containing the minimum requirements for the ABI. + * Public headers on some implementations also expose some implementation + * details. The layout of our subclasses must respect the layout of the + * C++ runtime library, but also needs to be portable across multiple + * implementations and so should not depend on internal symbols from those + * libraries. */ class type_info { @@ -95,14 +98,6 @@ namespace std type_info(const char *name): __type_name(name) { } public: const char* name() const { return __type_name; } - virtual bool __is_pointer_p() const; - virtual bool __is_function_p() const; - virtual bool __do_catch(const type_info *thrown_type, - void **thrown_object, - unsigned outer) const; - virtual bool __do_upcast( - const __class_type_info *target, - void **thrown_object) const; }; } @@ -226,15 +221,71 @@ namespace gnustep { namespace libobjc { - struct __objc_id_type_info : std::type_info + /** + * Superclass for the type info for Objective-C exceptions. + */ + struct __objc_type_info : std::type_info + { + /** + * Constructor that sets the name. + */ + __objc_type_info(const char *name) : type_info(name) {} + /** + * Helper function used by libsupc++ and libcxxrt to determine if + * this is a pointer type. If so, catches automatically + * dereference the pointer to the thrown pointer in + * `__cxa_begin_catch`. + */ + virtual bool __is_pointer_p() const { return true; } + /** + * Helper function used by libsupc++ and libcxxrt to determine if + * this is a function pointer type. Irrelevant for our purposes. + */ + virtual bool __is_function_p() const { return false; } + /** + * Catch handler. This is used in the C++ personality function. + * `thrown_type` is the type info of the thrown object, `this` is + * the type info at the catch site. `thrown_object` is a pointer + * to a pointer to the thrown object and may be adjusted by this + * function. + */ + virtual bool __do_catch(const type_info *thrown_type, + void **thrown_object, + unsigned) const + { + assert(0); + return false; + }; + /** + * Function used for `dynamic_cast` between two C++ class types in + * libsupc++ and libcxxrt. + * + * This should never be called on Objective-C types. + */ + virtual bool __do_upcast( + const __class_type_info *target, + void **thrown_object) const + { + assert(0); + return false; + }; + }; + /** + * Singleton type info for the `id` type. + */ + struct __objc_id_type_info : __objc_type_info { - __objc_id_type_info() : type_info("@id") {}; + /** + * The `id` type is mangled to `@id`, which is not a valid mangling + * of anything else. + */ + __objc_id_type_info() : __objc_type_info("@id") {}; virtual ~__objc_id_type_info(); virtual bool __do_catch(const type_info *thrownType, void **obj, unsigned outer) const; }; - struct __objc_class_type_info : std::type_info + struct __objc_class_type_info : __objc_type_info { virtual ~__objc_class_type_info(); virtual bool __do_catch(const type_info *thrownType, @@ -266,7 +317,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw || (AppleCompatibleMode && dynamic_cast(thrownType))) { - thrown = **(id**)obj; + thrown = *(id*)obj; // nil only matches id catch handlers in Apple-compatible mode, or when thrown as an id if (0 == thrown) { @@ -278,7 +329,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw } else if (dynamic_cast(thrownType)) { - thrown = **(id**)obj; + thrown = *(id*)obj; found = isKindOfClass((Class)objc_getClass(thrownType->name()), (Class)objc_getClass(name())); } @@ -296,12 +347,12 @@ bool gnustep::libobjc::__objc_id_type_info::__do_catch(const type_info *thrownTy // Id catch matches any ObjC throw if (dynamic_cast(thrownType)) { - *obj = **(id**)obj; + *obj = *(id*)obj; return true; } if (dynamic_cast(thrownType)) { - *obj = **(id**)obj; + *obj = *(id*)obj; return true; } return false;