Skip to content

Commit 3b88797

Browse files
committed
More EH fixes.
libsupc++ is more aggressive about internal consistency checks than libcxxrt, so we need to be more careful in the interop. The tests from PR #138 now pass for me on Debian with libsupc++.
1 parent be6483d commit 3b88797

File tree

2 files changed

+67
-34
lines changed

2 files changed

+67
-34
lines changed

eh_personality.c

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222

2323
void test_cxx_eh_implementation();
2424

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

2633
/**
2734
* Class of exceptions to distinguish between this and other exception types.
@@ -75,6 +82,35 @@ typedef enum
7582
handler_class
7683
} handler_type;
7784

85+
enum exception_type
86+
{
87+
NONE,
88+
CXX,
89+
OBJC,
90+
FOREIGN,
91+
BOXED_FOREIGN
92+
};
93+
struct thread_data
94+
{
95+
enum exception_type current_exception_type;
96+
id lastThrownObject;
97+
BOOL cxxCaughtException;
98+
struct objc_exception *caughtExceptions;
99+
};
100+
101+
static __thread struct thread_data thread_data;
102+
103+
static struct thread_data *get_thread_data(void)
104+
{
105+
return &thread_data;
106+
}
107+
108+
static struct thread_data *get_thread_data_fast(void)
109+
{
110+
return &thread_data;
111+
}
112+
113+
78114
/**
79115
* Saves the result of the landing pad that we have found. For ARM, this is
80116
* stored in the generic unwind structure, while on other platforms it is
@@ -147,13 +183,35 @@ static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
147183
unwindHeader)));
148184
*/
149185
}
186+
187+
void objc_exception_rethrow(struct _Unwind_Exception *e);
188+
150189
/**
151190
* Throws an Objective-C exception. This function is, unfortunately, used for
152191
* rethrowing caught exceptions too, even in @finally() blocks. Unfortunately,
153192
* this means that we have some problems if the exception is boxed.
154193
*/
155194
void objc_exception_throw(id object)
156195
{
196+
struct thread_data *td = get_thread_data();
197+
fprintf(stderr, "Throwing %p, in flight exception: %p\n", object, td->lastThrownObject);
198+
fprintf(stderr, "Exception caught by C++: %d\n", td->cxxCaughtException);
199+
// If C++ caught the exception, then we may need to make C++ rethrow it if
200+
// we want to preserve exception state. Rethrows should be handled with
201+
// objc_exception_rethrow, but clang appears to do the wrong thing for some
202+
// cases.
203+
if (td->cxxCaughtException)
204+
{
205+
// For catchalls, we may result in our being passed the pointer to the
206+
// object, not the object.
207+
if ((object == td->lastThrownObject) ||
208+
((object != nil) &&
209+
!isSmallObject(object) &&
210+
(*(id*)object == td->lastThrownObject)))
211+
{
212+
__cxa_rethrow();
213+
}
214+
}
157215

158216
SEL rethrow_sel = sel_registerName("rethrow");
159217
if ((nil != object) &&
@@ -175,6 +233,9 @@ void objc_exception_throw(id object)
175233

176234
ex->object = object;
177235

236+
td->lastThrownObject = object;
237+
td->cxxCaughtException = NO;
238+
178239
_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
179240
free(ex);
180241
if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception)
@@ -480,6 +541,7 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version,
480541
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
481542

482543
DEBUG_LOG("Installing context, selector %d\n", (int)selector);
544+
get_thread_data()->cxxCaughtException = NO;
483545
return _URC_INSTALL_CONTEXT;
484546
}
485547

@@ -513,48 +575,20 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
513575
int ret = CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
514576
exceptionObject->private_1 = ex->cxx_exception->private_1;
515577
exceptionObject->private_2 = ex->cxx_exception->private_2;
578+
if (ret == _URC_INSTALL_CONTEXT)
579+
{
580+
get_thread_data()->cxxCaughtException = YES;
581+
}
516582
return ret;
517583
}
518584
return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
519585
}
520586

521-
// Weak references to C++ runtime functions. We don't bother testing that
522-
// these are 0 before calling them, because if they are not resolved then we
523-
// should not be in a code path that involves a C++ exception.
524-
__attribute__((weak)) void *__cxa_begin_catch(void *e);
525-
__attribute__((weak)) void __cxa_end_catch(void);
526-
__attribute__((weak)) void __cxa_rethrow(void);
527-
528-
enum exception_type
529-
{
530-
NONE,
531-
CXX,
532-
OBJC,
533-
FOREIGN,
534-
BOXED_FOREIGN
535-
};
536-
struct thread_data
537-
{
538-
enum exception_type current_exception_type;
539-
struct objc_exception *caughtExceptions;
540-
};
541-
542-
static __thread struct thread_data thread_data;
543-
544-
static struct thread_data *get_thread_data(void)
545-
{
546-
return &thread_data;
547-
}
548-
549-
static struct thread_data *get_thread_data_fast(void)
550-
{
551-
return &thread_data;
552-
}
553-
554587
id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
555588
{
556589
struct thread_data *td = get_thread_data();
557590
DEBUG_LOG("Beginning catch %p\n", exceptionObject);
591+
td->cxxCaughtException = NO;
558592
if (exceptionObject->exception_class == objc_exception_class)
559593
{
560594
td->current_exception_type = OBJC;

objcxx_eh.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ namespace gnustep
266266
const __class_type_info *target,
267267
void **thrown_object) const
268268
{
269-
assert(0);
270269
return false;
271270
};
272271
};

0 commit comments

Comments
 (0)