Thread GC frees roots before thread actually finishes
In the following program, an IORef is garbage collected after a
NonTermination exception, but is subsequently accessed:
import Control.Exception as E import Data.IORef import System.Mem.Weak main :: IO () main = do ref <- newIORef 'x' weak <- mkWeakIORef ref $ putStrLn "IORef finalized" let check = deRefWeak weak >>= \m -> case m of Nothing -> putStrLn "IORef was GCed" Just ref' -> do x <- readIORef ref' putStrLn $ "IORef still alive, and contains " ++ show x let loop = loop check loop `catch` \ex -> do putStrLn $ "caught exception: " ++ show (ex :: SomeException) check readIORef ref >>= print
IORef still alive, and contains 'x' IORef finalized caught exception: <<loop>> IORef was GCed 'x'
The same happens with other thread deadlocks, such as:
- newEmptyMVar >>= takeMVar
- atomically retry
It does not happen when a
UserInterrupt exception is caught.
This also affects
ForeignPtr; see the attached "database" example. This is what really triggered #7170 (closed). I marked this "Runtime crash" because it can lead to a
ForeignPtr being accessed after the garbage collector finalized it.