Skip to content

Heap corruption with ForeignPtr

Looks like #14346 (closed) has been fixed for allocaBytes, but touch# is used in a other places. It could be useful to add some documentation about it to touch#. I noticed the comment on alloca and immediately realized that the same problem might be applicable to withForeignPtr, which it is:

module Main where

import Control.Concurrent
import Control.Monad
import Data.Word
import Foreign.Storable
import Foreign.ForeignPtr
import Numeric

main :: IO ()
main = do
  replicateM_ 49 $ threadDelay 1
  fptr <- mallocForeignPtrBytes 4
  withForeignPtr fptr $ \p ->
    forever $ do
      poke p (0xDEADBEEF :: Word32)
      threadDelay 10
      x <- peek p
      unless (x == 0xDEADBEEF) $ putStrLn (showHex x "")

Compiling it almost always results in a binary that will corrupt memory when executed and eventually results in a segfault:

$ stack --silent --resolver ghc-8.10.1 exec -- ghc -O2 -threaded -fforce-recomp Main.hs && ./Main
[1 of 1] Compiling Main             ( Main.hs, Main.o )
Linking Main ...
^C
$ stack --silent --resolver ghc-8.10.1 exec -- ghc -O2 -threaded -fforce-recomp Main.hs && ./Main
[1 of 1] Compiling Main             ( Main.hs, Main.o )
Linking Main ...
1fee80
4d2463
4d10aa
4d2541
498cd8
4d10aa
416c40
416c40
4d2463
4d2463
1f4370
1f4370
17018
1f4370
416c40
17018
Segmentation fault (core dumped)
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information