Skip to content

Concurrent generator iteration crashes the free-threaded build on 3.13 and 3.14 (gh-120321 fixes not backported) #156351

Description

@Meet-1010

Bug report

Bug description

Iterating a single generator from two threads hard-crashes the free-threaded
interpreter on 3.13.x and 3.14.x. The documented behaviour is
ValueError: generator already executing; instead the process dies with SIGSEGV,
SIGBUS, or Fatal Python error: _TAIL_CALL_CACHE: Executing a cache. on builds
configured --with-tail-call-interp. Because there is no Python-level exception,
the failure is uncatchable and takes the whole process down.

import sys, threading

def gen():
    while True:
        yield 1

g = gen()
barrier = threading.Barrier(2)

def worker():
    barrier.wait()
    for _ in range(3000):
        try:
            next(g)
        except ValueError:
            pass          # the documented, correct outcome

ts = [threading.Thread(target=worker) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print("survived", sys._is_gil_enabled())

This is gh-120321, which was closed on 2026-08-19. The fix series landed on
main only — every PR in it carries the 3.15 label and nothing was backported.
Objects/genobject.c on main contains 38 FT_ATOMIC_* operations guarding
generator frame-state transitions; the 3.14 and 3.13 branches contain none.

I am filing this separately rather than reopening gh-120321 because the fix there
is correct and complete for main — the question is only whether the supported
release lines should get it.

Reproduction matrix

20 runs per cell, macOS 15 / arm64 (Apple M5, 10 cores). Interpreters are the
python-build-standalone builds installed via uv python install; all are
--disable-gil, and the 3.14/3.15 ones additionally --with-tail-call-interp.

Interpreter 2 threads × 3,000 8 × 20,000 16 × 50,000 (yield from)
3.13.13 free-threaded 2/20 20/20 18/20
3.14.0 free-threaded 19/20 20/20 18/20
3.14.4 free-threaded 20/20 20/20 13/20
3.15.0a8 free-threaded 0/20 0/20 0/20
3.14.4 free-threaded, PYTHON_GIL=1 0/20 0/20 0/20
3.14.7, GIL build 0/20 0/20 0/20

150 crashes in 180 runs on the affected builds; 0 in 180 across all three
controls. The tail-call interpreter only changes how the corruption surfaces —
3.13.13t is built without it and still segfaults.

Observed signatures: rc=-11 (SIGSEGV), rc=-10 (SIGBUS),
Fatal Python error: _TAIL_CALL_CACHE: Executing a cache., and once
Fatal Python error: _PyEval_EvalFrameDefault.

Why it seems worth backporting

PEP 779 removed the experimental label from free-threading in 3.14, which is the
signal for projects to ship cp314t wheels and for users to run real workloads.
Sharing one generator across a thread pool is ordinary — itertools pipelines,
lazy readers, ThreadPoolExecutor.map over a generator — and the failure mode is
a silent process death rather than a catchable exception.

I looked at whether the series cherry-picks onto 3.14 and it does not: 8 of the 9
commits conflict, and the foundational one (gh-142599) is ~1,100 insertions
across 16 files including Python/bytecodes.c and the generated bytecode tables,
which depend on post-3.14 changes such as the SEND specialization. So this is a
request rather than an offer of a patch — I do not think a community backport of
this series would be responsible, and I would defer entirely to whoever owns the
original fix on whether a narrower change (for example making only the
gi_frame_state read/write in gen_send_ex2 atomic, so the re-entrancy guard
reliably raises ValueError) is worth doing on the stable branches.

CPython versions tested on

3.13, 3.14, 3.15

Operating systems tested on

macOS

Caveat

Reproduced on one platform only (macOS 15 / arm64). This is a data race, so
timing on other platforms will differ — the 3.13.13t two-thread cell (2/20) shows
how load-sensitive it is even on a single machine. Happy to run the matrix
elsewhere if that would help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions