diff options
author | Andreas Klebinger <klebinger.andreas@gmx.at> | 2019-12-17 16:29:54 +0100 |
---|---|---|
committer | Andreas Klebinger <klebinger.andreas@gmx.at> | 2019-12-17 16:47:13 +0100 |
commit | 59b265f4dd6104f518538c7cefa0dee574fb8ca9 (patch) | |
tree | e6b489b75851cf27f385552250b1b711e67f29e6 | |
parent | 62fa1f51e0bf6737520f65fac3057dc541b92632 (diff) | |
download | haskell-wip/winio-changes.tar.gz |
Fix input truncation when reading from handle.wip/winio-changes
This was caused by not upholding the read buffer invariant
that bufR == bufL == 0 for empty read buffers.
-rw-r--r-- | libraries/base/GHC/IO/Buffer.hs | 3 | ||||
-rw-r--r-- | libraries/base/GHC/IO/Handle/Text.hs | 37 |
2 files changed, 26 insertions, 14 deletions
diff --git a/libraries/base/GHC/IO/Buffer.hs b/libraries/base/GHC/IO/Buffer.hs index 5098e087d1..f169ae6f5f 100644 --- a/libraries/base/GHC/IO/Buffer.hs +++ b/libraries/base/GHC/IO/Buffer.hs @@ -305,7 +305,8 @@ summaryBuffer !buf -- Strict => slightly better code in if null p then "0x0" else '0':'x':p ppr x = x --- INVARIANTS on Buffers: +-- Note [INVARIANTS on Buffers] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- * r <= w -- * if r == w, and the buffer is for reading, then r == 0 && w == 0 -- * a write buffer is never full. If an operation diff --git a/libraries/base/GHC/IO/Handle/Text.hs b/libraries/base/GHC/IO/Handle/Text.hs index 7af1b450f4..f7a1e73f8c 100644 --- a/libraries/base/GHC/IO/Handle/Text.hs +++ b/libraries/base/GHC/IO/Handle/Text.hs @@ -826,12 +826,16 @@ hGetBuf h !ptr count bufReadNonEmpty :: Handle__ -> Buffer Word8 -> Ptr Word8 -> Int -> Int -> IO Int bufReadNonEmpty h_@Handle__{..} + -- w for width, r for ... read ptr? buf@Buffer{ bufRaw=raw, bufR=w, bufL=r, bufSize=sz } ptr !so_far !count = do debugIO ":: bufReadNonEmpty" + -- We use < instead of <= because for count == avail + -- we need to reset bufL and bufR to zero. + -- See also: INVARIANTS on Buffers let avail = w - r - if (count <= avail) + if (count < avail) then do copyFromRawBuffer ptr raw r count writeIORef haByteBuffer buf{ bufL = r + count } @@ -850,24 +854,28 @@ bufReadNonEmpty h_@Handle__{..} then return so_far' else bufReadEmpty h_ buf' ptr' so_far' remaining - +-- We want to read more data, but the buffer is empty. (buffL == buffR == 0) +-- See also Note [INVARIANTS on Buffers] in Buffer.hs bufReadEmpty :: Handle__ -> Buffer Word8 -> Ptr Word8 -> Int -> Int -> IO Int bufReadEmpty h_@Handle__{..} buf@Buffer{ bufRaw=raw, bufR=w, bufL=r, bufSize=sz, bufOffset=bff } ptr so_far count - | count > sz = do count <- loop haDevice 0 bff count - let buf1 = bufferAddOffset (fromIntegral count) buf - -- let buf2 = buf1 { bufR = w + count } - writeIORef haByteBuffer buf1 - debugIO ("bufReadEmpty: " ++ summaryBuffer buf1) - return count + | count > sz + = do + count <- loop haDevice 0 bff count + let buf1 = bufferAddOffset (fromIntegral count) buf + writeIORef haByteBuffer buf1 + debugIO ("bufReadEmpty: " ++ summaryBuffer buf1) + return count | otherwise = do - (r,buf') <- Buffered.fillReadBuffer haDevice buf - if r == 0 - then return so_far - else do writeIORef haByteBuffer buf' - bufReadNonEmpty h_ buf' ptr so_far count + (r,buf') <- Buffered.fillReadBuffer haDevice buf + if r == 0 + then return so_far + else do writeIORef haByteBuffer buf' + bufReadNonEmpty h_ buf' ptr so_far count where + -- Read @bytes@ byte into ptr. Repeating the read until either zero + -- bytes where read, or we are done reading. loop :: RawIO.RawIO dev => dev -> Int -> Word64 -> Int -> IO Int loop dev delta off bytes | bytes <= 0 = return (so_far + delta) loop dev delta off bytes = do @@ -985,6 +993,9 @@ bufReadNBNonEmpty h_@Handle__{..} ptr so_far count = do let avail = w - r + -- We use < instead of <= because for count == avail + -- we need to reset bufL and bufR to zero. + -- See also [INVARIANTS on Buffers] in Buffer.hs if (count < avail) then do copyFromRawBuffer ptr raw r count |