dotnet/wpf · error · System.IO.EndOfStreamException

SR.EndOfStreamReached

Error message

SR.EndOfStreamReached

What it means

BitStream.ReadByte attempts to read 1-8 bits from the underlying stream and throws EndOfStreamException(SR.EndOfStreamReached) when the stream is already exhausted (EndOfStream is true). The library signals that the caller asked for more bit data than the stream contains rather than returning a partial/zero value.

Solutions

  1. Check BitStream.EndOfStream before each ReadByte call and stop decoding when true.
  2. Validate that the ISF/stream data is complete (correct total length) before decoding.
  3. Catch EndOfStreamException around ISF decoding and treat the input as truncated/corrupt.
  4. Fix the loop bounds so the number of reads matches the actual byte/bit length of the stream.

Example fix

// before
while (i < packetCount)
    packets[i] = bitStream.ReadByte(8); // may overrun a short stream
// after
while (i < packetCount && !bitStream.EndOfStream)
    packets[i] = bitStream.ReadByte(8);
if (i < packetCount)
    throw new InvalidDataException("ISF stream truncated before all packets were read");
Defensive patterns

Strategy: validation

Validate before calling

if (bitStream.EndOfStream)
    return null; // or stop decoding
byte v = bitStream.ReadByte(countOfBits);

Type guard

static bool CanRead(BitStream s) => !s.EndOfStream;

Try / catch

try
{
    byte v = bitStream.ReadByte(8);
}
catch (EndOfStreamException)
{
    // stream exhausted: treat ISF data as truncated
    throw new InvalidDataException("ISF stream ended before all data was read");
}

Prevention

When it happens

Trigger: Calling ReadByte after all bytes in the stream have been consumed. Callers include GetDataFromReader, Uncompress, LoadPackets, and the indexer (b); truncated or mis-lengthed ISF/stroke data makes decoding overrun the buffer.

Common situations: Parsing a truncated or corrupted ISF file (incomplete download, bad save); a decoder loop that iterates a packet count larger than the data present.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/786d98b92b27ecae. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/Ink/BitStream.cs:230

        {
            byte b = ReadByte(1);
            return ((b & 1) == 1);
        }

        /// <summary>
        /// Read a specified number of bits from the stream into a single byte
        /// </summary>
        /// <param name="countOfBits">The number of bits to unpack</param>
        /// <returns>A single byte that contains up to 8 packed bits</returns>
        /// <remarks>For example, if 2 bits are read from the stream, then a full byte
        /// will be created with the least significant bits set to the 2 unpacked bits
        /// from the stream</remarks>
        internal byte ReadByte(int countOfBits)
        {
            // if the end of the stream has been reached, then throw an exception
            if (EndOfStream)
            {
                throw new System.IO.EndOfStreamException(SR.EndOfStreamReached);
            }

            // we only support 1-8 bits currently, not multiple bytes, and not 0 bits
            if (countOfBits > Native.BitsPerByte || countOfBits <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(countOfBits), countOfBits, SR.CountOfBitsOutOfRange);
            }

            if (countOfBits > _bufferLengthInBits)
            {
                throw new ArgumentOutOfRangeException(nameof(countOfBits), countOfBits, SR.CountOfBitsGreatThanRemainingBits);
            }

            _bufferLengthInBits -= (uint)countOfBits;

            // initialize return byte to 0 before reading from the cache
            byte returnByte = 0;

View on GitHub (pinned to 81131a70a4)