
#8926: GHC makes unsound references in object code ----------------------------+---------------------------------------------- Reporter: | Owner: anton.dubovik | Status: new Type: bug | Milestone: Priority: normal | Version: 7.6.3 Component: Compiler | Operating System: Unknown/Multiple Keywords: | Type of failure: GHC rejects valid program Architecture: | Test Case: Unknown/Multiple | Blocking: Difficulty: Unknown | Blocked By: | Related Tickets: | ----------------------------+---------------------------------------------- To reproduce the bug run script `run.sh` from the attached archive. It will: 1. install `FooPackage` {{{ Resolving dependencies... Configuring FooPackage-0.1... Building FooPackage-0.1... Preprocessing library FooPackage-0.1... [1 of 1] Compiling FooPackage ( src\FooPackage.hs, dist\build\FooPackage.o ) In-place registering FooPackage-0.1... Installing library in C:\Users\Anton\AppData\Roaming\cabal\i386-windows- ghc-7.6.3\FooPackage-0.1 Registering FooPackage-0.1... Installed FooPackage-0.1 }}} 2. compile executable `Client1` which depends on `FooPackage` {{{ [1 of 3] Compiling QuxClient ( QuxClient.hs, obj\QuxClient.o ) [2 of 3] Compiling BarClient ( BarClient.hs, obj\BarClient.o ) [3 of 3] Compiling Client1 ( Client1.hs, obj\Client1.o ) Linking exes/Client1.exe ... }}} 3. compile executable `Client2` which doesn't depend on `FooPackage` At the third step GHC will fall with linker error: {{{ [2 of 2] Compiling Client2 ( Client2.hs, obj\Client2.o ) Linking exes/Client2.exe ... obj\BarClient.o:fake:(.text+0x83): undefined reference to `FooPackagezm0zi1_FooPackage_zdsinsertzuzdsgo5_info' obj\BarClient.o:fake:(.data+0x10): undefined reference to `FooPackagezm0zi1_FooPackage_zdsinsertzuzdsgo5_closure' collect2: ld returned 1 exit status }}} Both `Client1` and `Client2` import `BarClient` module that doesn't depends on `FooPackage`. `Client1` imports `QuxClient` that imports `FooPackage`: {{{ module QuxClient where import FooPackage(foo) import Data.Set qux :: Set String -> Set String qux = foo }}} {{{ module BarClient where import Data.Set bar :: Set String -> Set String bar s = insert "bar" s }}} `FooPackage` uses function `Data.Set.insert` which is marked at `Data.Set` as `INLINABLE`: {{{ module FooPackage where import Data.Set foo :: Set String -> Set String foo s = insert "foo" s }}} GHC emphasizes in interface file, that `FooPackage.o` contains specialized version of `Data.Set.insert`: {{{
ghc --show-iface FooPackage.hi ... "SPEC Data.Set.Base.insert [GHC.Base.String]" [ALWAYS] forall $dOrd :: GHC.Classes.Ord GHC.Base.String Data.Set.Base.insert @ [GHC.Types.Char] $dOrd = FooPackage.$sinsert ... }}}
Later GHC see again the use of `Data.Set.insert@String` at `BarClient` and decides to apply this specialise rule, so that `BarClient` now has reference to `FooPackage`: {{{
ghc --show-iface BarClient.hi ... bar :: Data.Set.Base.Set GHC.Base.String -> Data.Set.Base.Set GHC.Base.String {- Arity: 1, Strictness: S, Unfolding: (\ s :: Data.Set.Base.Set GHC.Base.String -> FooPackage.$sinsert_$sgo5 BarClient.bar1 s) -} ... }}}
ghc-pkg list ... containers-0.5.0.0
`Client2` doesn't depend on `FooPackage`, thus linker throws an error. There are plenty of workarounds here, but all of them are ad hoc (1,2,3) or could affect performance (4): 1. Change the order of `BarClient` and `QuxClient` imports in `Client1` module. 2. Compile `Client1` and `Client2` in opposite order. 3. Add fake import at `Client2` module: {{{ import FooPackage() }}} 4. Build `FooPackage` with ghc-option `-fomit-interface-pragmas`. That will eraise from `FooPackage.hi` all specialisation rules as well as information about strictness and inlining. Some information about the environment: {{{ base-4.6.0.1 ...
ghc --version The Glorious Glasgow Haskell Compilation System, version 7.6.3 cabal --version cabal-install version 1.18.0.3 using version 1.18.1.3 of the Cabal library }}}
-- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8926 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler