Repository navigation
Fix PNG decoding of empty data chunks and short palettes, and use big-endian 16-bit tRNS - #3228
Merged
JimBobSquarePants merged 5 commits intoOct 27, 2026
Conversation
…big-endian 16-bit tRNS Zero-length IDAT and fdAT chunks are valid, but the data chunk readers returned their length of 0, which the inflater treats as the end of the compressed stream. An empty chunk inside the zlib header, or two in a row, broke decoding. The readers now skip empty chunks. A PLTE chunk shorter than one entry produced an empty color table, which the palette scanline processor indexed outside of. It is now treated as a missing palette, so decoding throws InvalidImageContentException. 16-bit grayscale and truecolor tRNS samples are big-endian, like all PNG multi-byte values, but were read and written little-endian.
4 tasks done
Validate indexed palettes before allocating pixels and reject frame data without a complete sequence number in every integrity mode. Reuse the pending-chunk path to return malformed fdAT chunks from inflation to the outer chunk loop. Keep IDAT payloads separate from frame-data framing. Extend existing chunk tests for CRC policies, empty frame payload layouts, short palettes and missing sequence numbers. Use the existing whole-image comparer instead of cloning every frame. All 463 PNG tests pass in Release on .NET 10.
4 tasks done
Load a stored noise PNG and the existing APNG through TestFile instead of generating random pixels and encoding baseline images for every case. Remove the image generator and defer baseline decoding until a pixel comparison is required.
Store all chunk layouts, corrupt-CRC variants, short palettes, truncated frame chunks and asymmetric 16-bit transparency samples as input files. Tests load those files without constructing or compressing PNG input. Encoder tests also load their input images from files. Remove six input-building helpers. Independently check every fixture for chunk bounds, CRC classification and payload contents; Pillow verifies unchanged pixels for all twelve valid rechunked inputs. All 463 PNG tests pass in Release on .NET 10.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisites
Description
This fixes three PNG defects: empty image-data chunks prematurely ended decompression, palettes shorter than one RGB entry could be indexed outside their storage, and 16-bit transparency markers used the wrong byte order.
The decoder skips valid empty IDAT payloads and sequence-only fdAT chunks without ending the compressed stream. Chunk parsing and CRC checks still use the existing reader. Only consecutive IDAT payloads belong to the default image's compressed stream; frame-data chunks return to the outer chunk loop for their framing checks.
Indexed images require a complete palette entry. That requirement is checked before allocating pixels and outside image-data recovery. fdAT chunks must also contain their four-byte sequence number. Short fdAT chunks encountered during decompression or Identify return through the existing pending-chunk path, so the outer loop rejects them in every integrity mode.
Both encoding and decoding now use big-endian 16-bit tRNS samples, as required by the PNG specification.
Integrity policy
Test inputs
All regression inputs are committed files, including the chunk layouts, corrupt CRCs, malformed palettes, truncated frame chunks and 16-bit transparency samples. Decoder tests do not construct, compress or rewrite input images. Encoder tests also load their input images from files. Six input-building helpers were removed. Offline verification checked all 25 variant files for chunk bounds, CRC classification and payload contents; Pillow independently confirmed unchanged pixels for all 12 valid rechunked PNG/APNG files.
Verification
Ten of the original fifteen regression cases fail on current main before the fix. Review tests also exposed suppressed missing-palette errors and accepted short frame-data chunks.
After correction, all 463 PNG tests pass in Release on .NET 10. This includes exact static and animated pixel comparisons, corrupt empty-chunk CRCs, malformed frame chunks at the start and during decompression, palette bounds, and independent checks of stored transparency bytes. The existing whole-image comparer checks every frame without cloning them for comparison.
The branch includes current main. No tolerances or reference images changed.
Fixes #3240