[Gc] C++ exceptions problem

Filip Pizlo pizlo at mac.com
Mon Jan 16 14:04:17 PST 2006


Just some clarification in this matter:  looking at the GCC 4.0  
source, it looks like the exception "slot" that a C++ exception is  
stored in while "in transit" is allocated using malloc.  The relevant  
code is in libstdc++-v3/libsupc++/eh_alloc.cc in the GCC source.  It  
seems that one hackish approach (other than asking the collector to  
override malloc/free) would be to override  
__cxxabicv1::__cxa_allocate_exception(size_t) and  
__cxxabiv1::__cxa_free_exception(void*).

But I don't like that approach, since the allocate_exception function  
needs to also do C++-runtime-specific bookkeeping.

To me it seems like it would be perfectly reasonable to patch the C++  
runtime so that the malloc/free routines that are used for exception- 
related allocation can be configured dynamically, say with a call like:

__gnu_ext::__set_exception_malloc(void *(*malloc)(size_t), void(*free) 
(void*)) throw();

This will require a small patch to the C++ runtime as well as a small  
addition to the GC (the collector could call this function during  
GC_INIT).  Thoughts?

--
Filip



On Jan 16, 2006, at 3:19 PM, Filip Pizlo wrote:

> Hello,
>
> It seems that there is a bad interaction between the collector and C 
> ++ exceptions.  When thrown, a C++ exception seems to be stored in  
> some thread-local storage arranged for by the runtime.  This  
> storage location is overlooked by the collector, so some roots are  
> missed.  Here's a simple program that demonstrates the problem:
>
> #include <gc/gc.h>
> #include <string.h>
> #include <stdio.h>
>
> struct myexc {
>     char *str;
> };
>
> void f() {
>     myexc e;
>     e.str=(char*)GC_MALLOC_ATOMIC(100);
>     strcpy(e.str,"hello, world!");
>     // uncomment for a cheap workaround
>     //char **strptr=(char**)GC_MALLOC_UNCOLLECTABLE(sizeof(char**));
>     //*strptr=e.str;
>     throw e;
> }
>
> void g() {
>     try {
>         f();
>     } catch (...) {
>         // if you don't see the bug, change 1000 to a bigger number  
> or do something else here
>         // that would force a GC.  to see correct behavior, comment  
> this loop out.
>         for (unsigned i=0;i<1000;++i) {
>             char *str=(char*)GC_MALLOC_ATOMIC(100);
>             strcpy(str,"foobar!");
>         }
>         throw;
>     }
> }
>
> int main() {
>     try {
>         g();
>     } catch (const myexc &e) {
>         printf("string is: %s\n",e.str);
>     }
>     return 0;
> }
>
> The correct behavior would be for the program to print:
>
> string is: hello, world!
>
> However, if the 1000 iteration loop causes a GC, we see the output:
>
> string is: foobar!
>
> I've tested this on GCC 3.3 and 4.0 on Mac OS X 10.4.3 and 10.4.4  
> with gc 6.5 and 6.6.  I've also tested this on an AMD64 machine  
> running Linux with GCC 3.4.  On the AMD64, I had to substantially  
> increase the number of iterations to see the bug, though.
>
> I wanted to test with latest from CVS, but the sourceforge CVS is  
> giving me issues right now.  So I tried with 7.0alpha5.  After  
> fixing a typo in gcconfig.h (#defined instead of #define), it  
> failed to compile on OS X with the error:
>
> mach_dep.c:194:3: #error GC_push_regs cannot be used with threads
>
> (I was using autoconf, and ./configured the collector with --enable- 
> threads=posix --enable-cplusplus --disable-shared --enable-static).
>
> On the AMD64 machine, 7.0alpha5 built happily, but still had the C+ 
> + exception problem.
>
> --
> Filip
>
>
> _______________________________________________
> Gc mailing list
> Gc at linux.hpl.hp.com
> http://www.hpl.hp.com/hosted/linux/mail-archives/gc/



More information about the Gc mailing list