GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-161792: Fix crashes in the callable iterator by nascheme · Pull Request #161793 · python/cpython

Conversation

@nascheme

@nascheme nascheme commented Nov 11, 2026

Copy link
Copy Markdown
Member

calliter_iternext() called it_callable and compared the result against it_sentinel through borrowed pointers.

  • In all builds, the sentinel's __eq__ can call __setstate__() and free the sentinel while the comparison is using it (uaf of it_sentinel in callable_iterator.__next__ #158031).
  • In the free-threaded build, another thread can free the fields by exhausting the iterator or calling __setstate__(), and two threads exhausting the iterator can both DECREF the callable (Crash when a callable iterator is shared between threads #161792).

Sharing a callable iterator between threads, or calling __setstate__() on one that is in use, is not supported: the values produced are unspecified. It must not crash, though. That lets the fix avoid a lock:

  • Readers load a field (acquire) and take a strong reference right away, before any code can run. The callable is held across the call and the sentinel across the comparison.
  • Writers (exhaustion and __setstate__()) swap the field with an atomic exchange, so only one thread gets the old value, and release it with _PyObject_XDecRefDelayed(). In the free-threaded build that defers the DECREF until no thread can still be between its load and its incref; in the default build it is a plain Py_XDECREF().

This also covers gh-158031, so it overlaps with #158046, which takes a strong reference to the sentinel only.

Performance

Release builds (Clang 20, no PGO/LTO), single thread pinned to one CPU, ns per item including consumption overhead (deque(islice(it, N), maxlen=0)), best of 7, mean of two runs.

Free-threaded build:

Workload main PR
iter(int, 1) 9.2 9.9
Python function, sentinel 1 24.4 25.5
Python function, object() sentinel 29.7 30.6
Python function, no sentinel 19.1 19.8
bound __next__ of itertools.repeat, sentinel 1 13.1 14.1

Default (GIL) build:

Workload main PR
iter(int, 1) 7.8 9.5
Python function, sentinel 1 21.0 21.7
Python function, object() sentinel 22.4 25.2
Python function, no sentinel 16.6 16.6
bound __next__ of itertools.repeat, sentinel 1 12.1 13.7

The cost is about 1 ns per item in the free-threaded build and 0-3 ns in the default build, from the strong references to the callable and sentinel. It is only visible when the callable is trivially cheap.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@nascheme
pythongh-161792: Fix crashes in the callable iterator
814a28b
calliter_iternext() used borrowed references to it_callable and
it_sentinel, which could be freed by __setstate__() during the call or
comparison (pythongh-158031), or by another thread in the free-threaded build.
Take strong references when reading the fields, and update them with an
atomic exchange plus a delayed DECREF.
@nascheme nascheme added the type-crash A hard crash of the interpreter, possibly with a core dump label Nov 11, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Nov 11, 2026
Crash when a callable iterator is shared between threads #161792
Open
@nascheme
nascheme marked this pull request as ready for review November 11, 2026 05:16
@bedevere-app bedevere-app Bot added the awaiting core review label Nov 11, 2026
@nascheme
nascheme requested a review from kumaraditya303 November 11, 2026 05:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@kumaraditya303 kumaraditya303 Awaiting requested review from kumaraditya303

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

awaiting core review type-crash A hard crash of the interpreter, possibly with a core dump

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@nascheme
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.