[GHC] #15338: ghc-pkg misbehaves after possible miscompilation on m68k and sh4
GHC
ghc-devs at haskell.org
Wed Jul 11 19:05:48 UTC 2018
#15338: ghc-pkg misbehaves after possible miscompilation on m68k and sh4
-------------------------------------+-------------------------------------
Reporter: glaubitz | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone: 8.6.1
Component: Compiler | Version: 8.4.3
Resolution: | Keywords:
Operating System: Linux | Architecture: m68k
Type of failure: Incorrect result | Test Case:
at runtime |
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by slyfox):
Replying to [comment:4 slyfox]:
> Normally '''COPY''' relocations are used only for immutable ('''const'''
in C land) data. But '''_closure'''s are mutable. I'll double-check
generated C code and file a toolchain bug upstream.
James (jrtc27) pointed out that '''COPY''' relocations are fine for
mutable data as long as shared library allows interposition of the symbol.
James also noted that GHC uses '''-Bsymbolic''' which forbids symbol
interposition and binds global symbols to library's definition.
'''-Bsymbolic''' is set in '''GHC'''s driver:
http://git.haskell.org/ghc.git/blob/HEAD:/compiler/main/SysTools.hs#l550
Thus smaller C-only reproducer that illustrates the problem is the
following:
{{{#!c
/* lib.c: */
int things[] = { 99,98,97,96 };
int shlib_f(int i) {
return things[i];
}
}}}
{{{#!c
/* bin.c */
#include <stdio.h>
/* declarations from lib.c */
extern int things[];
int shlib_f(int i);
int main() {
printf("main (before store): things[0] = %i\n", things[0]);
printf("shlib (before store): things[0] = %i\n", shlib_f(0));
things[0] = 45;
/* check if library sees 'things' changed. It should */
printf("main (after store): things[0] = %i\n", things[0]);
printf("shlib (after store): things[0] = %i\n", shlib_f(0));
return 0;
}
}}}
{{{#!sh
#/bin/bash
# a.sh
#cross=sh4-unknown-linux-gnu-
cc=${cross}gcc
cflags="-O1 -Wall"
$cc $cflags -shared -fPIC lib.c -o libbug.so
-Wl,-Bsymbolic
$cc $cflags -fno-PIC -fno-PIE -no-pie bin.c -o bug.no-pie -L.
-lbug -Wl,-rpath=.
$cc $cflags -fPIC -fPIE -pie bin.c -o bug.pie -L.
-lbug -Wl,-rpath=.
echo "target: ${cross}; emulator=${emulator}; no-pie:"
${emulator} ./bug.no-pie
echo "target: ${cross}; emulator=${emulator}; pie:"
${emulator} ./bug.pie
}}}
Here we define a shared library with '''things''' global symbol and
'''shlib_f()''' that refers to that global symbol. Here is how things
break (even on '''x86_64'''):
{{{
$ cross=x86_64-pc-linux-gnu- emulator= ./a.sh
target: x86_64-pc-linux-gnu-; emulator=; no-pie:
main (before store): things[0] = 99
shlib (before store): things[0] = 99
main (after store): things[0] = 45
shlib (after store): things[0] = 99
target: x86_64-pc-linux-gnu-; emulator=; pie:
main (before store): things[0] = 99
shlib (before store): things[0] = 99
main (after store): things[0] = 45
shlib (after store): things[0] = 99
}}}
Note: the value of '''things[0]''' disagrees between binary and library
copy. That's how we get '''stdout''' closure evaluated twice. It matter
because '''stdout''' is devined via '''unsafePerformIO''':
{{{#!hs
-- libraries/base/GHC/IO/Handle/FD.hs
stdout :: Handle
{-# NOINLINE stdout #-}
stdout = unsafePerformIO $ do
-- ToDo: acquire lock
setBinaryMode FD.stdout
enc <- getLocaleEncoding
mkHandle FD.stdout "<stdout>" WriteHandle True (Just enc)
nativeNewlineMode{-translate newlines-}
(Just stdHandleFinalizer) Nothing
}}}
Here we effectively allocate the buffer cache as many times as
'''stdout''' is evaluated. This breaks the invariant of
'''unsafePerformIO''' being evaluated only once.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15338#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list