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