gifio, jpegio: a header ahead of its check, and lengths that overreport - #11384
Merged
tannewt merged 2 commits intoSep 15, 2026
Merged
Conversation
OnDiskGif read all_args[0] rather than the parsed argument, so a fully keyword call opened a file named after the keyword. GifWriter.add_frame wrote the frame's nineteen byte header before the check that bounds the source buffer, so a short frame raised but left the header in the file. The check moves ahead of it and replaces the three per-branch checks that came after. GifWriter's buffer is sized as nblocks * 128 + 4, which covers the block data but not the 416 byte header the constructor writes into the same buffer first; a 14 by 9 frame gives one block and an allocation of 132 bytes. write_data only asserts, and the assert is compiled out of a release build. jpegio's discard path returned the length it was asked for rather than the length it read, so a stream that ended early was reported as fully skipped. Its two early exits subtracted the same rect origin from each side, reducing each test to comparing a limit with itself, which cannot hold.
Author
|
Testing and diagnostic script. |
Member
|
Do we have tests we can add for these fixes too? |
tannewt
added this pull request to the merge queue
Sep 14, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Sep 14, 2026
tannewt
added this pull request to the merge queue
Sep 15, 2026
tyeth
pushed a commit
to tyeth/circuitpython
that referenced
this pull request
Oct 3, 2026
The PWM section used a plain literal for the machine.PWM class name while every other IO section on the page (Pin, UART, ADC, SPI, I2C, etc.) links to the corresponding library page via a :ref: role. Use the same cross-reference so the link is clickable. Fixes adafruit#11384. Signed-off-by: Andrii Anoshyn <anoshyn.andrii@gmail.com>
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.
Code written by Claude Code, guided and corrected by @peterbay.
The problem
Five defects in
gifioandjpegio: an argument read from the wrong place, a header written before the data behind it was checked, a buffer sized for the frames but not for the header that goes in first, and two length results that report more than happened.The changes
OnDiskGifread its filename from the wrong place. The constructor tookall_args[0]rather than the parsed argument, so a fully keyword call handed it the keyword rather than the value:OnDiskGif(filename="/x.gif")tried to open a file calledfilename.GifWriter.add_framewrote the frame header before checking the frame. Nineteen bytes — the graphic control extension and the image descriptor — went out ahead of themp_get_indexthat bounds the source buffer, so a short frame raised but left its header behind. The check moves ahead of the header, where it also replaces the three per-branch checks that followed it.GifWriter's buffer was sized for a frame, not for the header.nblocks * 128 + 4covers the block data, but the constructor first writes a fixed header into the same buffer: six bytes of signature, the screen descriptor, a 384 byte palette and the loop extension, 416 bytes in all. For a small frame that is more than the buffer holds — 14 by 9 pixels gives one block and an allocation of 132 bytes.write_datadoes not flush, it only asserts, and the assert is compiled out of a release build.jpegio's discard path reported the full length at end of stream. It returns what it actually read now, so the decoder is not told it passed over data that was not there.jpegio's two early exits compared a value with itself. Both tests subtracted the same rect origin from each side, soy2 < y1reduced tolim.y2 < lim.y1andx2 < x1tolim.x2 < lim.x1, neither of which can hold for a valid limit. They compare against the block instead.Testing
Seeed XIAO nRF52840 Sense, on two builds differing only by these changes.
OnDiskGif(filename="/test.gif")OSError: [Errno 2] No such file/directory: filenameOnDiskGif("/test.gif")positionallydeinitThe buffer size is arithmetic rather than a measurement: the same test prints that the constructor writes 416 bytes, and the allocation for a 14 by 9 frame is
1 * 128 + 4. Nothing visible happens on this board — the write goes into whatever the allocator handed out next and the test finished before anything read it back.The two
jpegiochanges do not alter what comes out. The early exits are a short cut out of work that the copy loop below them clips away anyway, so the pixels are the same either way; a limit rect and a truncated file both decoded identically on the two builds. They are corrected because the tests as written cannot fire, not because the output was wrong.No new translatable strings.