Skip to content

Fix: free the PNG row pointers when libpng reports an error - #874

Open
DTW-Thalion wants to merge 1 commit into
gnustep:masterfrom
DTW-Thalion:fix/png-decoder-leak
Open

Fix: free the PNG row pointers when libpng reports an error#874
DTW-Thalion wants to merge 1 commit into
gnustep:masterfrom
DTW-Thalion:fix/png-decoder-leak

Conversation

@DTW-Thalion

Copy link
Copy Markdown
Contributor

-_initBitmapFromPNG: holds the decoded buffer and the row pointer array in plain locals. Both are assigned after setjmp() and read again in the longjmp() handler, where the value of a local that has been written since the setjmp call is indeterminate. In practice one of them is held in a register that longjmp restores to its earlier value, so the handler sees NULL and skips the free. A PNG that libpng rejects part way through decoding therefore leaks the row pointer array, which holds one pointer per row of the height declared in the header.

Declaring the two pointers volatile makes them survive the jump. The bitmap data planes argument now takes a plain copy of the buffer pointer, since it wants an unqualified one.

Tests/gui/NSBitmapImageRep/pngAllocationOverflow.m already covers this: it feeds a 2148 by 1000000 image that libpng rejects with "Not enough image data".

Run gnustep-tests from Tests/gui. 4353 assertions pass and one is a dashed hope, before and after.

Built with base and gui GNUSTEP_WITH_ASAN=1, that test goes from leaking 8000000 bytes in one allocation to leaking nothing, and no other test program's leak total changes.

-_initBitmapFromPNG: keeps the decoded buffer and the row pointer array in
plain locals. Both are set after setjmp() and read again in the longjmp()
handler, where their values are indeterminate: a local held in a register is
restored to what it was at the setjmp call, so the handler can see NULL and
skip the free. Decoding a PNG that libpng rejects part way through leaked the
row pointer array, one pointer per row of the declared image height.

Declare the two pointers volatile so they survive the jump. The bitmap data
planes argument takes a plain copy, since it wants an unqualified pointer.
@DTW-Thalion
DTW-Thalion requested a review from fredkiefer as a code owner July 30, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant