FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Protect getlist() walk with a critical section (free-threading, #9852) by espressolee · Pull Request #9854 · python-pillow/Pillow · GitHub

Protect getlist() walk with a critical section (free-threading, #9852) - #9854

Closed
espressolee wants to merge 1 commit into
python-pillow:mainfrom
espressolee:ft-getlist-critical-section
Closed

Protect getlist() walk with a critical section (free-threading, #9852)#9854
espressolee wants to merge 1 commit into
python-pillow:mainfrom
espressolee:ft-getlist-critical-section

Conversation

espressolee commented Aug 5, 2026
edited by radarhere
Loading

Copy link
Copy Markdown

Fixes #9852. Alternative to #9853

getlist() (used by Image.point()) walks the caller's list with PySequence_Fast and the unchecked PySequence_Fast_GET_ITEM macro over a size captured earlier in the function. On a free-threaded build PySequence_Fast returns the list itself for a list input, so the walk aliases the caller's list; another thread resizing it drives an out-of-bounds read and a segfault. This is #9852.

This holds a critical section on the fast sequence for the walk and clamps the loop to its current length, so a resize that happened between the earlier size read and the walk cannot read out of bounds. It mirrors the critical-section approach already used for FontObject in #9498, and uses the Py_BEGIN_CRITICAL_SECTION shim already vendored in thirdparty/pythoncapi_compat.h (a no-op block on < 3.13, where the GIL serialises the walk anyway).

Verification

python3.14.0rc1t, built from source:

A concurrent resize now yields a truncated read rather than a crash; if you'd prefer it to raise instead, I'm happy to adjust.

🤖 Generated with Claude Code

getlist() (used by Image.point()) walks the caller's list via PySequence_Fast
and the unchecked PySequence_Fast_GET_ITEM macro over a size captured earlier.
On a free-threaded build a concurrent resize of that list drives an
out-of-bounds read and a segfault (python-pillow#9852).

Hold a critical section on the fast sequence during the walk and clamp the loop
to its current length, mirroring the approach used for FontObject in python-pillow#9498.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copy link
Copy Markdown
Author

Cross-referencing #9853 — that PR was opened before this one and it fixes the free-threading race in getlist(): wrapping getlist_impl in Py_BEGIN_CRITICAL_SECTION(arg) puts PySequence_Size inside the section as well, so the count and the walk see the same object state. Priority is @lazerg's and I am happy for that one to land instead of this.

I will hold this PR open but idle rather than pushing changes to it, and follow whatever the maintainers prefer.

Copy link
Copy Markdown
Author

Closing in favour of #9853, which was opened first and is the better-scoped fix.

It takes the critical section on arg around the whole of getlist(), which also covers the
PySequence_Size() → PySequence_Fast() window; this PR took it on seq around the loop only.
For a list those are the same object, but for a non-list seq is a fresh object no other thread
can reach, so locking it does nothing and arg is the one that matters.

The other half of this PR — clamping the walk to PySequence_Fast_GET_SIZE(seq) — is a separate,
non-threading bug: n comes from the caller's __len__ and PySequence_Fast builds by
iterating, so they need not agree. It is being raised separately, and with a better fix than the
clamp: read n from the sequence and let the existing wrong_length check fire, so the caller
gets an error instead of a silently zero-filled result. Discussion in #9853.

#9852 remains the issue of record for the race. Nothing here is lost; it is only in two better
places.

espressolee closed this Aug 8, 2026
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

Labels

🤖-assisted AI-assisted Free-threading PEP 703 support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Free-threaded: Image.point(list) crashes if another thread mutates the list (getlist / PySequence_Fast, stale size)

2 participants


Back | FazBrowse Home | New Git URL