Opened 12 months ago

#8926 new bug

GHC makes unsound references in object code

Reported by: anton.dubovik Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.6.3
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: GHC rejects valid program Test Case:
Blocked By: Blocking:
Related Tickets: Differential Revisions:


To reproduce the bug run script 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
Registering FooPackage-0.1...
Installed FooPackage-0.1
  1. 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 ...
  1. 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
  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) -}

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:

> ghc-pkg list 
> ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3
> cabal --version
cabal-install version
using version of the Cabal library

Attachments (1) (2.3 KB) - added by anton.dubovik 12 months ago.
Run to reproduce the bug.

Download all attachments as: .zip

Change History (1)

Changed 12 months ago by anton.dubovik

Run to reproduce the bug.

Note: See TracTickets for help on using tickets.