On Sun, 03 Mar 2013 07:01:11 -0500, Benjamin Thaut <[email protected]> wrote:

When modules are initialized, druntime will first run the module initializers before running the module tls initializers ignoring the dependencies between the modules. This will lead to a access of a unitialized module if the module ctor of one module uses tls data of another module. Example:

module a:

class TLSStuff
{
   public int i;
}

TLSStuff g_tlsStuff;

static this()
{
   g_tlsStuff = new TLSStuff();
}

module b:
import a;

shared static this()
{
   g_tlsStuff.i++; //null pointer access
}

Is this a bug, or is this intended beahvior? I always believed that with all the dependency detenction that is done such situation should not happen.

As has been discussed, this is intended behavior.

But I will go a bit further. It is reasonable to assume that each thread being allocated will be assured that the shared data has already been initialized. This makes logical sense as the shared data is initialized once, thread data is initialized whenever you start a new one.

So if we had the shared data depending on the first thread local data being initialized, you couldn't have ANY thread local data depending on the shared data being initialized. I don't think this is the right decision.

But how can we solve this problem? One possibility, while a bit awkward, is to identify when you are initializing the first thread. Then use that knowledge to your advantage:

__gshared bool inFirstThread = true;

static this()
{
if(inFirstThread) // shared constructor already has initialized tls stuff for us
      inFirstThread = false;
   else
      g_tlsStuff = new TLSStuff();
}

shared static this()
{
   // initialize main thread's tls stuff
   g_tlsStuff = new TLSStuff();
   g_tlsStuff.i++;
}

If you needed this idiom elsewhere, you could set the inFirstThread to false as the first statement in main. Druntime could conceivably do something like this for you, if you are so inclined, file an enhancement.

-Steve

Reply via email to