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
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 ()

_______________________________________________
Glasgow-haskell-bugs mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to