Skip to content

Thunk is incorrectly updated on async exception in GHCi

The following program produces different results depending on whether it is compiled or interpreted:

import Control.Concurrent
import Control.Exception
import System.IO.Unsafe

main :: IO ()
main = do
  let io_thunk = unsafePerformIO $ threadDelay 1000000 *> pure ()
  eval_thread <- forkIO (evaluate io_thunk *> pure ())
  threadDelay 500000
  killThread eval_thread
  print io_thunk

When compiled, the program prints (), but when interpreted, it terminates with an exception:

$ ghc A.hs
[1 of 2] Compiling Main             ( A.hs, A.o )
[2 of 2] Linking A
$ ./A
()
$ ghc --run A.hs
<interactive>: thread killed

It seems like io_thunk is somehow being incorrectly overwritten as if the async exception were in fact raised synchronously.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information