[Gc] C++ exceptions problem

Boehm, Hans hans.boehm at hp.com
Tue Jan 17 17:20:26 PST 2006


It seems to me there are really two issues here:

1) The garbage collect cannot reliably find thread local memory, since
there seems to be no interface to enumerate it.  This is a well-known
problem which keeps recurring.  A portable solution appears impossible,
but I think that even a glibc/ELF only solution would be useful.  The
gcc/glibc/ELF tls ABI is described in a long document at
http://people.redhat.com/drepper/tls.pdf .  It appears possible to find
thread locals not associated with dlopened libraries by tracing from the
mapped region around the thread pointer, though that may be gross
overkill, and we would have to avoid accidentally tracing the entire
stack region.  I'd be inclined to ask the glibc developers for better
suggestions first.  But if we don't get a better offer, that seems to be
the right thing to do.

2) C++ exception values are allocated with malloc.  And hence if they
contain any pointers to the GC heap, and the exception is in transit
while a GC happens, the target object is not traced, and may be
collected prematurely.  This also really requires a glibc hook.

I think the test program here requires a fix to (1) if you want to
redirect the standard malloc to GC_malloc, and a fix to (2) if you
don't.  Really we need solutions to both.  Agreed?

Hans

> -----Original Message-----
> From: gc-bounces at napali.hpl.hp.com 
> [mailto:gc-bounces at napali.hpl.hp.com] On Behalf Of Filip Pizlo
> Sent: Monday, January 16, 2006 10:35 PM
> To: gc at napali.hpl.hp.com
> Cc: filip at cs.purdue.edu; jv at cs.purdue.edu; hosking at cs.purdue.edu
> Subject: Re: [Gc] C++ exceptions problem
> 
> 
> (Sorry if this is too many mails.)  I implemented something 
> like this  
> in the C++ runtime that ships with GCC 4.0.2.  And of course, it  
> makes C++ exceptions work correctly.
> 
> I am just curious, is this the best way of solving this problem?  Or  
> am I overlooking a simpler solution?
> 
> --
> Filip
> 
> 
> On Jan 16, 2006, at 5:04 PM, Filip Pizlo wrote:
> 
> > 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/
> >
> > _______________________________________________
> > Gc mailing list
> > Gc at linux.hpl.hp.com 
> > http://www.hpl.hp.com/hosted/linux/mail-archives/gc/
> 
> _______________________________________________
> 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