Skip to content

Throw PngFormatException on truncated input instead of hanging - #15

Merged
Zeejfps merged 1 commit into
Zeejfps:mainfrom
z1c0:fix/truncated-stream-hang
Nov 14, 2026
Merged

Zeejfps merged 1 commit into
Zeejfps:mainfrom
z1c0:fix/truncated-stream-hang

Conversation

@z1c0

@z1c0 z1c0 commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #14.

Problem

ReadIdatChunkDataIntoStream and ReadChunkData loop until a chunk's byte count has been read, but Stream.Read returns 0 at the end of the stream, so a file that ends inside an IDAT chunk, or inside a skipped ancillary chunk, never finishes decoding (100 % CPU, no exception). Two smaller cases of the same kind: ReadByte turned EOF (-1) into 0xFF, and ReadBytes let EndOfStreamException escape, which isn't one of the exceptions documented on Png.Decode*.

Change

All four paths in PngReader now throw PngFormatException("Unexpected end of stream: the PNG data is truncated."). No public API changes.

Tests

New TruncatedPngTests:

  • truncated inside IDAT
  • truncated inside an unknown ancillary chunk (abCd, goes through ReadChunkData)
  • every prefix png[..n] of a valid 16x16 RGBA PNG must throw PngFormatException

Each decode runs with a timeout, so a regression fails the test and doesn't hang the test run.

  • With the fix: all 212 tests pass (dotnet test -c Release, .NET 10 SDK).
  • Without it: all 3 new tests fail (the two hangs time out; the empty prefix throws EndOfStreamException).

🤖 Generated with Claude Code

ReadIdatChunkDataIntoStream and ReadChunkData looped until the chunk's
byte count was read, but Stream.Read returns 0 at the end of the stream,
so a file ending inside an IDAT or a skipped ancillary chunk never
finished decoding. ReadByte turned EOF (-1) into 0xFF, and ReadBytes let
EndOfStreamException escape, which isn't one of the documented exceptions.

All four now throw PngFormatException. A test decodes every prefix of a
valid PNG and expects that exception for each.

Fixes Zeejfps#14

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Zeejfps
Zeejfps merged commit a91f2b0 into Zeejfps:main Nov 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decoder hangs forever on a PNG truncated inside an IDAT chunk

2 participants