diff --git a/eh_personality.c b/eh_personality.c index c117077..0b41b63 100644 --- a/eh_personality.c +++ b/eh_personality.c @@ -78,13 +78,6 @@ Class get_type_table_entry(struct _Unwind_Context *context, static BOOL isKindOfClass(Class thrown, Class type, BOOL foreignException) { - // Nil is a catchall, but we only want to catch things that are not foreign - // exceptions in it. - if (Nil == type) - { - return (Nil != thrown) && !foreignException; - } - do { if (thrown == type) @@ -114,6 +107,12 @@ static BOOL check_action_record(struct _Unwind_Context *context, if (filter > 0) { Class type = get_type_table_entry(context, lsda, filter); + // If the handler is a cleanup, we don't want to do mark it as a + // handler, but we might unwind through it. + if (Nil == type) + { + return YES; + } if (isKindOfClass(thrown_class, type, foreignException)) { return YES; @@ -203,12 +202,16 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version, // TODO: If this is a C++ exception, we can cache the lookup and cheat a // bit - id object = nil; + void *object = nil; if (!(actions & _UA_HANDLER_FRAME)) { struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr); action = dwarf_eh_find_callsite(context, &lsda); + // If there's no cleanup here, continue unwinding. if (0 == action.landing_pad) { return _URC_CONTINUE_UNWIND; } + // If there is a cleanup, we need to return the exception structure + // (not the object) to the calling frame. The exception object + object = exceptionObject; selector = 0; } else if (foreignException) @@ -230,7 +233,6 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version, object = ex->object; } - _Unwind_SetIP(context, (unsigned long)action.landing_pad); _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (unsigned long)object);