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

Reply via email to