[release/3.0] Fix BinaryReader.ReadChars for fragmented Streams (#26324) (#26356)
authorJan Kotas <jkotas@microsoft.com>
Mon, 26 Aug 2019 15:04:09 +0000 (08:04 -0700)
committerGitHub <noreply@github.com>
Mon, 26 Aug 2019 15:04:09 +0000 (08:04 -0700)
BinaryReader.ReadChars incorrectly read more than necessary from the underlying Stream when multi-byte characters straddled the read chunks.

Fixes https://github.com/dotnet/corefx/issues/40455

src/System.Private.CoreLib/shared/System/IO/BinaryReader.cs
src/System.Private.CoreLib/shared/System/Text/DecoderNLS.cs

index 560c998..037088c 100644 (file)
@@ -390,6 +390,28 @@ namespace System.IO
                 {
                     numBytes <<= 1;
                 }
+
+                // We do not want to read even a single byte more than necessary.
+                //
+                // Subtract pending bytes that the decoder may be holding onto. This assumes that each
+                // decoded char corresponds to one or more bytes. Note that custom encodings or encodings with
+                // a custom replacement sequence may violate this assumption.
+                if (numBytes > 1)
+                {
+                    DecoderNLS? decoder = _decoder as DecoderNLS;
+                    // For internal decoders, we can check whether the decoder has any pending state.
+                    // For custom decoders, assume that the decoder has pending state.
+                    if (decoder == null || decoder.HasState)
+                    {
+                        numBytes -= 1;
+
+                        // The worst case is charsRemaining = 2 and UTF32Decoder holding onto 3 pending bytes. We need to read just
+                        // one byte in this case.
+                        if (_2BytesPerChar && numBytes > 2)
+                            numBytes -= 2;
+                    }
+                }
+
                 if (numBytes > MaxCharBytesSize)
                 {
                     numBytes = MaxCharBytesSize;
index 184d59d..8cb3fff 100644 (file)
@@ -227,7 +227,7 @@ namespace System.Text
         {
             get
             {
-                return false;
+                return _leftoverByteCount != 0;
             }
         }