Segfault upon modifying immutable AA in static this

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jan 24 16:58:04 PST 2015


On Saturday, January 24, 2015 13:24:01 Nordlöw via Digitalmars-d-learn wrote:
> This snippet
>
>      static immutable words = [ `zero`, `one`, `two` ];
>
>      static immutable ubyte[string] wordsAA;
>
>      static this()
>      {
>          foreach (ubyte i, e; words) { wordsAA[e] = i; }
>      }
>
> compiles and links on dmd git master but run segfaults.
>
> Removing immutable qualifier from wordsAA avoids the segfeault.
>
> Are static module ctors allowed to modify immutable data or this
> a DMD bug?

immutable variables can only be initialized and cannot be assigned to. The
fact that

wordsAA[e] = i;

even compiles is most definitely a bug, but constructors are of a bit of a
special place for immutable variables, since they can be initialized there
rather than being directly initialized, and clearly something in how that is
handled in the compiler is buggy. i.e. code like

wordsAA = value;

would be illegal outside of a constructor, because wordsAA is immutable, but
it's legal, because it's inside of a constructor associated with it (in this
case, a static constructor for a static variable). So, presumably, whatever
in the compiler makes that legal has a bug that makes it think that

wordsAA[e] = i;

is legal when it isn't.

In any case, if you want to initialize an immutable array or AA or whatnot
where you can't just directly initialize it but rather need multiple
operations, then you need to create a mutable one that gets converted to an
immutable one - either by casting it to immutable when assigning it to the
immutable variable (in which case, you need to be sure that no mutable
reference to it continues to exist) or by writing a pure function to create
it and return it, in which case, it will implicitly convert to immutable,
because the compiler knows that no mutuable references to it exist.  So,
something like this should work

static immutable words = [ `zero`, `one`, `two` ];
static immutable ubyte[string] wordsAA;

static this()
{
    auto initWordsAA() pure
    {
        ubyte[string] retval;
        foreach(ubyte i, e; words)
            retval[e] = i;
        return retval;
    }
    wordsAA = initWordsAA();
}

You should report the segfault as a bug though. Your original code should
not compile, because

wordsAA[e] = i;

is quite illegal due to wordsAA's immutability.

- Jonathan M Davis




More information about the Digitalmars-d-learn mailing list