D Library Breakage

Jonathan Marler johnnymarler at gmail.com
Thu Apr 12 20:39:33 UTC 2018


Currently phobos is going through a transition where DIP 1000 is 
being enabled.  This presents a unique problem because when DIP 
1000 is enabled, it will cause certain functions to be mangled 
differently.  This means that if a module in phobos was compiled 
with DIP 1000 enabled and you don't enable it when compiling your 
application, you can end up with cryptic linker errors that are 
difficult to root cause.

This problem has exposed what I think to be a deeper problem with 
the way D handles precompiled modules. Namely:

Precompiled D libraries do not expose the "important compiler 
configuration" that was used to compile them.  "Important 
compiler configuration" meaning what versions were used, whether 
unittest was enabled, basically anything that an application 
using it needs to know to properly interpret the module the same 
way it was interpreted when it was compiled.

For example, say you have a library foo with a single module.

module foo;

struct Foo
{
     int x;
     version (FatFoo)
     {
         private int[100] y;
     }
     void init() @safe nothrow
     {
         x = 0;
         version (FatFoo)
         {
             y[] = 0;
         }
     }
}

Now let's compile it:

dmd -c foo.d

Now let's use it:

import foo;

int main() @safe nothrow
{
     Foo foo;
     foo.init();
     return 0;
}

dmd main.d foo.o   (foo.obj for windows)
./main             (main.exe for windows)

It runs and we're good to go.  Now let's do something sinister...

dmd -version=FatFoo -c foo.d

Now compile and run our program again, but don't include the 
`-version=FatFoo`

dmd main.d foo.o   (foo.obj for windows)
./main             (main.exe for windows)

We've just stomped all over our stack and now it's just a pancake 
of zeros!  Your results will be unpredictable but on my windows 
box main throws an exception even though the function is marked 
@safe and nothrow :)

The root of the problem in this situation comes back to the 
problem that DIP 1000 is currently having.  The "important 
compiler configuration" used to compile our library is unknown.  
If we could take our precompiled library foo.o and see what 
compiler configuration was used to compile it, we wouldn't have 
this problem because we would have seen it was compiled with the 
"FatFoo" version.  Then we would have interpreted the module we 
used to load it with the "FatFoo" version and avoided this 
terrible "pancake stack" :)

So what do people think?  Is this something we should address?  
We could explore ways of including information in our 
pre-compiled libraries that the compiler could use to know how it 
was compiled and therefore how to interpret the modules the same 
way they were when being compiled.  All object formats that I 
know of support sections that tools can use to inject information 
like this. We could also just tell people that they must make 
sure to use the same compiler configuration for their own 
applications that were used when their libraries were compiled.  
If they don't ensure this then all safety guarantees are 
gone...not ideal but less work for D right? :)






More information about the Digitalmars-d mailing list