gcc41 -v Using built-in specs. Target: i386-portbld-freebsd5.4 Configured with: ./..//gcc-4.1-20050709/configure --disable-rpath --disable-nls --with-system-zlib --with-libiconv-prefix=/usr/local --program-suffix=41 --libdir=/usr/local/lib/gcc/i386-portbld-freebsd5.4/4.1.0 --with-gxx-include-dir=/usr/local/lib/gcc/i386-portbld-freebsd5.4/4.1.0/include/c++/ --disable-shared --disable-libgcj --prefix=/usr/local i386-portbld-freebsd5.4 Thread model: posix gcc version 4.1.0 20050709 (experimental)
Problem: Objective-C programs with @finally block will abort() in _Unwind_Resume when leaving the @finally block while exception is thrown. Example program: ------------------------------------------------ #include <objc/Object.h> int thrower_try_body() { printf("Thrower try body\n"); return (0); } int finally_body() { printf("Finally body\n"); return (0); } int thrower() { @try { thrower_try_body(); @throw [Object new]; } @finally { finally_body(); } // <----- program aborts here. return 0; } int main(int ac, char *av[]) { @try { thrower(); } @catch (id exc) { printf("Got exception of class %s\n", [[exc class] name]); [exc free]; } } ----------------------------------------------- The @finally block in thrower function code generated from exception throwing : 8048f94: e8 0c 62 00 00 call 804f1a5 <objc_exception_throw> (exception value in %eax saved to stack) 8048f99: 89 45 f4 mov %eax,0xfffffff4(%ebp) 8048f9c: 8b 5d f4 mov 0xfffffff4(%ebp),%ebx 8048f9f: e8 89 ff ff ff call 8048f2d <finally_body> 8048fa4: 89 5d f4 mov %ebx,0xfffffff4(%ebp) 8048fa7: 83 ec 0c sub $0xc,%esp 8048faa: ff 75 f4 pushl 0xfffffff4(%ebp) (exception value restored and passed to _Unwind_Resume) 8048fad: e8 12 ca 00 00 call 80559c4 <_Unwind_Resume> _Unwind_Resume (gcc/unwind.inc) requires (struct _Unwind_Exception *) or derived (struct ObjcException*) argument, so passing exception value ((struct Object*) in this case) causes it to abort() (due to bad exception class). Proposed solution: The __gnu_objc_personality_v0 (and propably *_sj0 also) in exception.c should return the exception structure in case saw_cleanup is set. Otherwise, it should return the exception value (As it is now), but _Unwind_DeleteException the exception calloc'ed in objc_exception_throw if personality is not in _UA_SEARCH_PHASE. Patch fixing __gnu_objc_personality_v0: ---------------------------------------- --- libobjc.old/exception.c Wed Jul 13 15:59:46 2005 +++ libobjc/exception.c Wed Jul 13 16:59:45 2005 @@ -165,7 +165,8 @@ const unsigned char *p; _Unwind_Ptr landing_pad, ip; int handler_switch_value; - int saw_cleanup, saw_handler; + int saw_cleanup=0, saw_handler; + id return_object; /* Interface version check. */ if (version != 1) @@ -334,8 +335,14 @@ } install_context: + if (saw_cleanup==0) + { + return_object = xh->value; + if (!(actions & _UA_SEARCH_PHASE)) + _Unwind_DeleteException(&xh->base); + } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), - __builtin_extend_pointer (xh->value)); + __builtin_extend_pointer (saw_cleanup ? xh : return_object)); _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), handler_switch_value); _Unwind_SetIP (context, landing_pad); --------8<-------------8<-------------------- Patched version works and does not leak exception structures nor accesses free'd memory (tested with valgrind). -- Summary: [PATCH] Abort after @finally: libobjc passing exception value instead of exception. Product: gcc Version: 4.1.0 Status: UNCONFIRMED Severity: normal Priority: P2 Component: libobjc AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: creep at desk dot pl CC: gcc-bugs at gcc dot gnu dot org GCC build triplet: 4.1.0 20050709 GCC host triplet: i386-portbld-freebsd5.4 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22492