Skip to content

Commit

Permalink
Use the C++ runtime to check for uncaught C++ exceptions.
Browse files Browse the repository at this point in the history
As discussed in #152, use the function defined in the Itanium C++ ABI to
check whether the thrown exception is the current caught C++ exception
and needs rethrowing via `__cxa_rethrow()`.
  • Loading branch information
David Chisnall authored and triplef committed Dec 23, 2021
1 parent 81677b6 commit 7dcd112
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions eh_personality.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,32 @@
#endif

void test_cxx_eh_implementation();
/**
* The Itanium C++ public structure for in-flight exception status.
*/
struct __cxa_eh_globals
{
/**
* The head exception object. By convention, this is actually the end of
* the `__cxa_exception` structure and points to the address of the thrown
* object. This is either an `id*` or a pointer to a C++ type that we're
* not going to look at.
*/
struct __cxa_exception *caughtExceptions;
/**
* The number of in-flight exceptions thrown.
*/
unsigned int uncaughtExceptions;
};


// Weak references to C++ runtime functions. We don't bother testing that
// these are 0 before calling them, because if they are not resolved then we
// should not be in a code path that involves a C++ exception.
__attribute__((weak)) void *__cxa_begin_catch(void *e);
__attribute__((weak)) void __cxa_end_catch(void);
__attribute__((weak)) void __cxa_rethrow(void);
__attribute__((weak)) struct __cxa_eh_globals *__cxa_get_globals(void);


/**
Expand Down Expand Up @@ -93,7 +112,6 @@ enum exception_type
struct thread_data
{
enum exception_type current_exception_type;
id lastThrownObject;
BOOL cxxCaughtException;
struct objc_exception *caughtExceptions;
};
Expand Down Expand Up @@ -202,12 +220,9 @@ void objc_exception_throw(id object)
// cases.
if (td->cxxCaughtException)
{
// For catchalls, we may result in our being passed the pointer to the
// object, not the object.
if ((object == td->lastThrownObject) ||
((object != nil) &&
!isSmallObject(object) &&
(*(id*)object == td->lastThrownObject)))
struct __cxa_eh_globals *globals = __cxa_get_globals();
if ((globals->caughtExceptions != NULL) &&
(*(id*)globals->caughtExceptions == object))
{
__cxa_rethrow();
}
Expand All @@ -233,7 +248,6 @@ void objc_exception_throw(id object)

ex->object = object;

td->lastThrownObject = object;
td->cxxCaughtException = NO;

_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
Expand Down

0 comments on commit 7dcd112

Please sign in to comment.