`withForeignPtr` is unsafe
Similarly to #14346 (closed), the following program triggers a segfault:
import Control.Concurrent
import Control.Monad
import Data.Word
import Foreign.ForeignPtr
import Foreign.Storable
import System.Mem
main :: IO ()
main = do
fp <- mallocForeignPtrBytes 40000
_ <- forkIO $ do
-- withForeignPtr is supposed to keep `p` alive but it wasn't the case
withForeignPtr fp $ \p -> do
forever $ do
performGC
-- We need to perform at least two operations here on the pointer.
-- By doing so, the loop worker takes an Addr# as a parameter.
-- Otherwise `byteArrayContents` is used here (instead of in the
-- caller) and the ByteArray used by the ForeignPtr implementation is
-- kept alive even with `touch#` removed.
poke p (0xDEADBEEF :: Word32)
poke p (0x12345678 :: Word32)
--touchForeignPtr fp
yield
threadDelay 1000
withForeignPtr
doesn't keep p
alive because touch#
becomes unreachable due to the use of forever
.
Making withForeignPtr
NOINLINE fixes the bug.
Edited by Ömer Sinan Ağacan