SegFault caused by some IO+Arrays+GC interaction
Tomasz Zielonka
t.zielonka at students.mimuw.edu.pl
Sun Jun 27 18:36:50 EDT 2004
Hello!
The attached program uses no unsafe operations and yet it segfaults from
time to time. Try it on some file of moderate size, like:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.2.1
$ ghc -O --make Bug -o Bug
Chasing modules from: Bug
Compiling Main ( Bug.hs, Bug.o )
Linking ...
$ ls -l /etc/termcap
-rw-r--r-- 1 root root 737535 lip 20 2001 /etc/termcap
$ ./Bug < /etc/termcap > /dev/null
Segmentation fault (core dumped)
$ ./Bug < /etc/termcap > /dev/null
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.2.1
$ gcc --version
gcc (GCC) 3.3.3
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
$ uname -a
Linux green.local.gem.pl 2.4.18-10 #1 Wed Aug 7 10:26:48 EDT 2002 i686
unknown
Notice that this program calls performGC after every processed word
and commenting this out seems to eliminate the problem. Perhaps this
is a silly thing to do, but I don't think it should result in SEGV.
If this qualifies as a bug, tell me if I can do anything to help you
nail it down.
Best regards,
Tom
--
.signature: Too many levels of symbolic links
-------------- next part --------------
import Data.Array.IO
import Data.Array.Unboxed
import Data.Array.Base
import Data.Array.ST
import Data.Word
import System.IO
import System.IO.Unsafe
import Control.Monad.ST
import Control.Monad
import System.Mem
main :: IO ()
main = do
ws <- getArrayWords
(`mapM_` ws) $ \w -> do
ioarr <- thaw w
putArray ioarr
putStrLn ""
performGC
putArray :: IOUArray Int Word8 -> IO ()
putArray arr = do
when (rangeSize (bounds arr) > 0) $ hPutArray stdout arr (rangeSize (bounds arr))
getArrays :: IO [UArray Int Word8]
getArrays = {- unsafeInterleaveIO $ -} do
ioarr <- newArray (0, blockSize-1) 0 :: IO (IOUArray Int Word8)
n <- hGetArray stdin ioarr blockSize
case n of
0 -> do
return []
_ | n > 0 -> do
arr0 <- freeze ioarr
arr <-
if n < blockSize
then do
return (array (0, n-1) [ (i, arr0 ! i) | i <- [0..n-1] ])
else do
return arr0
arrs <- getArrays
return (arr : arrs)
where
blockSize :: Int
blockSize = 2 ^ (16 :: Int)
findInArray p arr pos =
loop pos
where
rbound = snd (bounds arr)
loop i | i > rbound = Nothing
| p (arr ! i) = Just i
| otherwise = loop $! (i + 1)
getArrayWords :: IO [UArray Int Word8]
getArrayWords = do
blocks <- getArrays
return (buildWords 0 blocks)
where
buildWords pos bs =
skipWhiteSpace pos bs $
\pos bs ->
case findInBuffers isWhite pos bs of
Just (Right whitePos) ->
takeArray pos bs whitePos $
\w pos bs -> w : buildWords pos bs
Just (Left charsLeft) ->
takeArray pos bs charsLeft $
\w pos bs -> [w]
Nothing ->
[]
findInBuffers :: (Word8 -> Bool) -> Int -> [UArray Int Word8] -> Maybe (Either Int Int)
findInBuffers = findInBuffersAcc 0
where
findInBuffersAcc acc p pos (buf:bufs) =
case findInArray p buf pos of
Just nlPos -> Just (Right (acc + nlPos - pos))
Nothing -> (findInBuffersAcc $! acc + snd (bounds buf) - pos + 1) p 0 bufs
findInBuffersAcc 0 _ _ [] = Nothing
findInBuffersAcc acc _ _ [] = Just (Left acc)
isWhite :: Word8 -> Bool
isWhite c = c == 10 || c == 13 || c == 9 || c == 32
skipWhiteSpace pos (bufs@(b:bs)) cont
| not (isWhite (b ! pos)) = cont pos bufs
| pos == snd (bounds b) = skipWhiteSpace 0 bs cont
| otherwise = (skipWhiteSpace $! (pos+1)) bufs cont
skipWhiteSpace pos [] cont = cont pos []
takeArray pos0 bs0 len cont =
runST (do
marr <- newArray (0, len-1) 0 :: ST s (STUArray s Int Word8)
fillArray marr 0 pos0 bs0
)
where
fillArray marr marrPos pos bufs = do
if marrPos == len
then do
arr <- freeze marr
return (cont arr pos bufs)
else do
let (b:bs) = bufs
remain = len - marrPos
inThisArray = snd (bounds b) - pos + 1
if inThisArray <= remain
then do
copyFromArray b pos marr marrPos inThisArray
fillArray marr (marrPos + inThisArray) 0 bs
else do
-- inThisArray > remain
copyFromArray b pos marr marrPos remain
fillArray marr (marrPos + remain) (pos + remain) (b:bs)
copyFromArray src srcPos dst dstPos count
| count > 0 = do
writeArray dst dstPos (src ! srcPos)
((copyFromArray src $! (srcPos+1)) dst $! (dstPos+1)) $! (count-1)
| otherwise = do
return ()
More information about the Glasgow-haskell-bugs
mailing list