[commit: base] master: Fix #7522 by checking for empty byte buffers a little more (d714cc4)

Max Bolingbroke batterseapower at hotmail.com
Wed Apr 10 22:24:57 CEST 2013


Repository : ssh://darcs.haskell.org//srv/darcs/packages/base

On branch  : master

https://github.com/ghc/packages-base/commit/d714cc4ac2f889407f5baf004044bbe913e79249

>---------------------------------------------------------------

commit d714cc4ac2f889407f5baf004044bbe913e79249
Author: Max Bolingbroke <batterseapower at hotmail.com>
Date:   Wed Apr 10 21:13:28 2013 +0100

    Fix #7522 by checking for empty byte buffers a little more
    
    Quite a few lines have changed but that is mostly comments.

>---------------------------------------------------------------

 GHC/IO/Encoding/Types.hs   |   13 +++++--------
 GHC/IO/Handle/Internals.hs |   32 +++++++++++++++++++++++++++++---
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/GHC/IO/Encoding/Types.hs b/GHC/IO/Encoding/Types.hs
index 6147d01..e31c067 100644
--- a/GHC/IO/Encoding/Types.hs
+++ b/GHC/IO/Encoding/Types.hs
@@ -41,17 +41,14 @@ data BufferCodec from to state = BufferCodec {
    -- if there is either not enough room in @to@, or @from@ does not
    -- contain a complete multibyte sequence.
    --
+   -- If multiple CodingProgress returns are possible, OutputUnderflow must be
+   -- preferred to InvalidSequence. This allows GHC's IO library to assume that
+   -- if we observe InvalidSequence there is at least a single element available
+   -- in the output buffer.
+   --
    -- The fact that as many elements as possible are translated is used by the IO
    -- library in order to report translation errors at the point they
    -- actually occur, rather than when the buffer is translated.
-   --
-   -- To allow us to use iconv as a BufferCode efficiently, character buffers are
-   -- defined to contain lone surrogates instead of those private use characters that
-   -- are used for roundtripping. Thus, Chars poked and peeked from a character buffer
-   -- must undergo surrogatifyRoundtripCharacter and desurrogatifyRoundtripCharacter
-   -- respectively.
-   --
-   -- For more information on this, see Note [Roundtripping] in GHC.IO.Encoding.Failure.
   
   recover :: Buffer from -> Buffer to -> IO (Buffer from, Buffer to),
    -- ^ The @recover@ function is used to continue decoding
diff --git a/GHC/IO/Handle/Internals.hs b/GHC/IO/Handle/Internals.hs
index 79228d3..855e31c 100644
--- a/GHC/IO/Handle/Internals.hs
+++ b/GHC/IO/Handle/Internals.hs
@@ -378,7 +378,15 @@ streamEncode codec from to = go (from, to)
       -- underflow particularly, and we want to delay errors about invalid
       -- sequences as far as possible.
       case why of
-        Encoding.InvalidSequence | bufL from == bufL from' -> recover codec from' to' >>= go
+        Encoding.InvalidSequence | bufL from == bufL from' -> do
+          -- NB: it is OK to call recover here. Because we saw InvalidSequence, by the invariants
+          -- on "encode" it must be the case that there is at least one elements available in the output
+          -- buffer. Furthermore, clearly there is at least one element in the input buffer since we found
+          -- something invalid there!
+          --debugIO $ "Before streamEncode recovery: from=" ++ summaryBuffer from' ++ ", to=" ++ summaryBuffer to'
+          (from', to') <- recover codec from' to'
+          --debugIO $ "After streamEncode recovery: from=" ++ summaryBuffer from' ++ ", to=" ++ summaryBuffer to'
+          go (from', to')
         _ -> return (from', to')
 
 -- -----------------------------------------------------------------------------
@@ -802,6 +810,16 @@ debugIO s
 -- Read characters into the provided buffer.  Return when any
 -- characters are available; raise an exception if the end of 
 -- file is reached.
+--
+-- In uses of readTextDevice within base, the input buffer is either:
+--   * empty
+--   * or contains a single \r (when doing newline translation)
+--
+-- The input character buffer must have a capacity at least 1 greater
+-- than the number of elements it currently contains.
+--
+-- Users of this function expect that the buffer returned contains
+-- at least 1 more character than the input buffer.
 readTextDevice :: Handle__ -> CharBuffer -> IO CharBuffer
 readTextDevice h_ at Handle__{..} cbuf = do
   --
@@ -832,9 +850,13 @@ readTextDevice h_ at Handle__{..} cbuf = do
   debugIO ("readTextDevice after decoding: cbuf=" ++ summaryBuffer cbuf' ++ 
         " bbuf=" ++ summaryBuffer bbuf2)
 
+  -- We can't return from readTextDevice without reading at least a single extra character,
+  -- so check that we have managed to achieve that
   writeIORef haByteBuffer bbuf2
-  if bufR cbuf' == bufR cbuf -- no new characters
-     then readTextDevice' h_ bbuf2 cbuf -- we need more bytes to make a Char
+  if bufR cbuf' == bufR cbuf
+     -- we need more bytes to make a Char. NB: bbuf2 may be empty (even though bbuf1 wasn't) when we
+     -- are using an encoding that can skip bytes without outputting characters, such as UTF8//IGNORE
+     then readTextDevice' h_ bbuf2 cbuf
      else return cbuf'
 
 -- we have an incomplete byte sequence at the end of the buffer: try to
@@ -853,7 +875,11 @@ readTextDevice' h_ at Handle__{..} bbuf0 cbuf0 = do
   (r,bbuf2) <- Buffered.fillReadBuffer haDevice bbuf1
   if r == 0
    then do
+     -- bbuf2 can be empty here when we encounter an invalid byte sequence at the end of the input
+     -- with a //IGNORE codec which consumes bytes without outputting characters
+     if isEmptyBuffer bbuf2 then ioe_EOF else do
      (bbuf3, cbuf1) <- recover decoder bbuf2 cbuf0
+     debugIO ("readTextDevice' after recovery: bbuf=" ++ summaryBuffer bbuf3 ++ ", cbuf=" ++ summaryBuffer cbuf1)
      writeIORef haByteBuffer bbuf3
      -- We should recursively invoke readTextDevice after recovery,
      -- if recovery did not add at least one new character to the buffer:





More information about the ghc-commits mailing list