tests: Test that we can throw and catch the same exception multiple times sequentially. (#188)

This originally came up as an issue with libc++abi support (#152), but is not specific to that ABI.

* Use the C++ runtime to check for uncaught C++ exceptions.

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()`.

Co-authored-by: Niels Grewe <grewe@ocean-insights.com>
Co-authored-by: David Chisnall <gnustep@theravensnest.org>
main
Frederik Seiffert 4 years ago committed by GitHub
parent 14619f2905
commit a357cb999c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -143,6 +143,7 @@ addtest_variants("CXXExceptions" "CXXException.m;CXXException.cc" true)
addtest_variants("ForwardDeclareProtocolAccess" "ForwardDeclareProtocolAccess.m;ForwardDeclareProtocol.m" true)
if (ENABLE_OBJCXX)
addtest_variants(ObjCXXEHInterop "ObjCXXEHInterop.mm;ObjCXXEHInterop.m" true)
addtest_variants(ObjCXXEHInteropTwice "ObjCXXEHInteropTwice.mm" true)
# This test is failing on Win32, but not for any obvious reason. Disable
# it for now to keep CI happy.
if (WIN32)

@ -0,0 +1,22 @@
#import "Test.h"
#import "stdio.h"
void excerciseExceptionCXX(Test *e) {
@try {
printf("Raising Test\n");
@throw e;
} @catch (Test *localException) {
printf("Caught\n");
}
}
int main(void)
{
Test *e = [Test new];
excerciseExceptionCXX(e);
excerciseExceptionCXX(e);
[e release];
}

@ -21,6 +21,24 @@
#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
@ -28,6 +46,7 @@ void test_cxx_eh_implementation();
__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);
/**
@ -93,7 +112,6 @@ enum exception_type
struct thread_data
{
enum exception_type current_exception_type;
id lastThrownObject;
BOOL cxxCaughtException;
struct objc_exception *caughtExceptions;
};
@ -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();
}
@ -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);

Loading…
Cancel
Save