[Gc] C++ exceptions problem

Boehm, Hans hans.boehm at hp.com
Wed Jan 18 12:09:33 PST 2006



> -----Original Message-----
> From: Filip Pizlo [mailto:pizlo at mac.com] 
> Sent: Tuesday, January 17, 2006 5:54 PM
> To: Boehm, Hans
> Cc: gc at napali.hpl.hp.com; filip at cs.purdue.edu; 
> jv at cs.purdue.edu; hosking at cs.purdue.edu
> Subject: Re: [Gc] C++ exceptions problem
> 
> 
> Hans,
> 
> > 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. ...
> 
> I haven't been following this problem.  Is there a place I can look  
> that summarizes the issues?  In particular, I am wondering why a  
> simple redirect trick wouldn't work for pthread specifics.
The issue here is really with __thread allocated thread-local-storage.
It has come up periodically on the gc list.  It is currently preventing
use of the (7.0alpha) collector as a malloc preload library with threads
enabled, since some glibc data structure ends up getting collected,
since it's only referenced from tls memory.

In general, pthread_...specific often tends not to be that interesting
anymore since, although unlike __thread it's actually officially
standardized, it's much slower.  The GC's thread local allocation
mechanism implements its own version, which I believe is usually
actually faster, though more restrictive, than the libpthread version.
> 
> > 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?
> 
> Right - it took me a while to see that. :-)  (You can't have the  
> exception storage allocated with GC_malloc, because then it'll get  
> prematurely deallocated.)
> 
> However, my hack seems like it would cover both issues: if GC_INIT  
> tells libstdc++ to use GC_malloc_uncollectable/GC_free for 
> allocation/ 
> deallocation, then regardless of the traceability of the 
> thread-local  
> mechanism used behind the scenes, things should sort of just work.   
> Right?
Agreed.  The issue then is really with other uses of tls.

> 
> Filip
> 
> 
> 
> >
> > 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