Skip to content

Commit

Permalink
More C++ exception fixes.
Browse files Browse the repository at this point in the history
 * Make sure the unwind state is synchronised between the Objective-C
   and C++ exception objects.
 * Reintroduce the is-pointer callback so that `__cxa_begin_catch`
   adjusts the pointer correctly.  Objective-C++ code uses
   `__cxa_begin_catch` without the `objc_begin_catch` wrapper and the
   runtime does not call the `__do_catch` method on the type info if the
   type info is an exact match, so the caught object ended up being a
   pointer to the object.  This also meant that we needed to remove the
   double dereference in the `__do_catch` methods.
 * Introduce a subclass of `std::type_info` for all Objective-C types
   and move the `virtual` functions there.  This should simplify
   supporting libc++abi.
  • Loading branch information
davidchisnall committed May 2, 2020
1 parent d5973fb commit ec5c0bc
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 22 deletions.
13 changes: 9 additions & 4 deletions eh_personality.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
Expand Down
87 changes: 69 additions & 18 deletions objcxx_eh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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;
};
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -266,7 +317,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw
|| (AppleCompatibleMode &&
dynamic_cast<const __objc_class_type_info*>(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)
{
Expand All @@ -278,7 +329,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw
}
else if (dynamic_cast<const __objc_class_type_info*>(thrownType))
{
thrown = **(id**)obj;
thrown = *(id*)obj;
found = isKindOfClass((Class)objc_getClass(thrownType->name()),
(Class)objc_getClass(name()));
}
Expand All @@ -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<const __objc_class_type_info*>(thrownType))
{
*obj = **(id**)obj;
*obj = *(id*)obj;
return true;
}
if (dynamic_cast<const __objc_id_type_info*>(thrownType))
{
*obj = **(id**)obj;
*obj = *(id*)obj;
return true;
}
return false;
Expand Down

0 comments on commit ec5c0bc

Please sign in to comment.