[Gc] C++ exceptions problem

Filip Pizlo pizlo at mac.com
Tue Jan 17 17:53:35 PST 2006


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

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.

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

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