[D-runtime] DLL initialization in Druntime

Rainer Schuetze r.sagitario at gmx.de
Sun Jan 16 09:54:18 PST 2011


Hi,

I have not updated to the latest version yet, but it seems that it's the 
first time that gc_addRange is called during initialization, and this 
hits the bug in the gc stub code (obviously, the return statements are 
missing for the "proxy is null" case).

Even if fixed, the proxy has the problem that anything that has been 
allocated until the proxy is switched, uses a different heap, because 
the C-Runtime is not shared between the DLLs. This will cause problems 
when trying to scan/collect objects.

I've proposed using a phobos.dll shared between DLLs, but it involves 
some trickery: http://d.puremagic.com/issues/show_bug.cgi?id=4071

BTW: there is a regression in 2.051 regarding DLLs in a multi-threading
environment: http://d.puremagic.com/issues/show_bug.cgi?id=5382

Rainer

Walter Bright wrote:
> It was failing hard with the latest changes on loading Windows DLLs, so 
> I looked into it.
> 
> I don't see how it ever could have worked.
> 
> Note that DLLs link with gcstub.obj, this is because DLLs share the gc 
> with the caller's gc, instead of having a separate gc that fights the 
> caller's. The general idea is that upon initialization the DLL sets 
> "proxy" to point to the caller's gc, and then all gc calls are routed 
> through the proxy.
> 
> First, in our DLL's DllMain(), we call:
> 
>         case DLL_PROCESS_ATTACH:
>             dll_process_attach(hInstance);
> 
> In dll_process_attach(), druntime calls:
> 
>     Runtime.initialize()
> 
> which calls:
> 
>     rt_init(null)
> 
> which calls:
> 
>    gc_init();
>    initStaticDataGC();
> 
> which calls:
> 
>     gcstub.gc.gc_addRange()
> 
> which looks like:
> 
> extern (C) void gc_addRange( void* p, size_t sz )
> {
>     printf("gcstub::gc_addRange() proxy = %p\n", proxy);
>     if( proxy is null )
>     {
>         Range* r = cast(Range*) realloc( ranges,
>                                          (nranges+1) * ranges[0].sizeof );
>         if( r is null )
>             onOutOfMemoryError();
>         r[nranges].pos = p;
>         r[nranges].len = sz;
>         ranges = r;
>         ++nranges;
>     }
>     return proxy.gc_addRange( p, sz );
> }
> 
> which will ALWAYS crash because proxy is null. But we never notice the 
> crash, because rt_init() ignores exceptions when dg is null, as in:
> 
>     catch (Throwable e)
>     {
>         if (dg)
>             dg(e);
>     }
> 
> and things then proceed with a half-crashed uninitialized runtime.
> 
> *Bugs:*
> 
> 1. proxy is null. It is supposed to be initialized by rt_loadLibrary(). 
> But, sadly, it dll_process_attach() gets called first by LoadLibrary()! 
> Disaster.
> 
> 2. gcstub's gc_addRange() and gc_addRoot() will always crash if proxy is 
> null.
> 
> 3. gc_isCollecting() needs to be added to gcstub.gc. Otherwise, the 
> linker mixes in gcstub with the regular gc in a truly frankensteinian mess.
> 
> 4. rt_init() should not ignore exceptions when dg is null, it should 
> rethrow them.
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> D-runtime mailing list
> D-runtime at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/d-runtime




More information about the D-runtime mailing list