[GHC] #8935: Obscure linker bug leads to crash in GHCi
GHC
ghc-devs at haskell.org
Fri Mar 28 14:26:01 UTC 2014
#8935: Obscure linker bug leads to crash in GHCi
------------------------------------+-------------------------------------
Reporter: simonmar | Owner: simonmar
Type: bug | Status: new
Priority: high | Milestone: 7.8.2
Component: Runtime System | Version: 7.6.3
Keywords: | Operating System: Unknown/Multiple
Architecture: Unknown/Multiple | Type of failure: GHCi crash
Difficulty: Rocket Science | Test Case:
Blocked By: | Blocking:
Related Tickets: |
------------------------------------+-------------------------------------
I have a build of GHC (with `DYNAMIC_GHC_PROGRAMS=NO`) that exhibits the
following crash:
{{{
$ ghc -e 'System.Environment.getEnvironment'
<segfault>
}}}
I tracked it down, eventually, to a bad reference to the symbol `environ`
from `__hscore_environ` in `libraries/base/includes/HsBase.h`. Somehow,
`environ` had got linked to the wrong address.
Lots more investigation lead me to discover this: `internal_dlsym()` in
`Linker.c` tries to look up a symbol in all the different shared libraries
we have loaded so far, one by one. (see
be497c202b790999c3fd0ddc4a4176b8cf6acf7e). Unfortunately, this seems to
break things in my case. Here's a simple test program that works on
Ubuntu 12.04:
{{{
#include <dlfcn.h>
#include <stdio.h>
char *so = "/usr/lib/x86_64-linux-gnu/libgmp.so";
char *so2 = "/usr/lib/x86_64-linux-gnu/libpthread.so";
extern char**environ;
int main(int argc, char *argv[])
{
void *deflt, *hdl;
deflt = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
printf("environ = %p\n", &environ);
printf("dlsym(deflt, \"environ\") = %p\n", dlsym(deflt,"environ"));
hdl = dlopen(so, RTLD_LAZY);
printf("dlsym(\"libgmp\", \"environ\") = %p\n", dlsym(hdl,"environ"));
hdl = dlopen(so2, RTLD_LAZY);
printf("dlsym(\"libpthread\", \"environ\") = %p\n",
dlsym(hdl,"environ"));
}
}}}
And the output:
{{{
environ = 0x601040
dlsym(deflt, "environ") = 0x601040
dlsym("libgmp", "environ") = 0x2aaaab290568
dlsym("libpthread", "environ") = 0x601040
}}}
Note that the value we get from looking up `environ` in `libgmp` is
different to the others. The correct value is `0x601040`. gdb thinks
that `0x2aaaab290568` is also `environ`:
{{{
(gdb) p4 0x2aaaab290568
0x2aaaab290580 <buflen.9817>: 0x0
0x2aaaab290578: 0x0
0x2aaaab290570 <miss_F_GETOWN_EX>: 0x0
0x2aaaab290568 <environ>: 0x0
}}}
but note that it contains zero. The real one is:
{{{
(gdb) p4 0x601040
0x601058: 0x0
0x601050 <dtor_idx.6533>: 0x0
0x601048 <completed.6531>: 0x0
0x601040 <environ@@GLIBC_2.2.5>: 0x7fffffffe268
}}}
In GHC we're loading `libgmp` when we load the `integer-gmp` package, and
this causes future references to `environ` to go wrong.
I've locally fixed this by changing `internal_dlsym` to `dlsym`, but since
there was a reason to make this change in the first place I haven't pushed
it to master. Suggestions welcome.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8935>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list