Skip to content

N-12 borrowed field reads are unsound on free-threaded 3.15t #193

Open

Description

@b-re-w

Defect (design, not yet implemented code)

docs/design/typedpython.md §4.3.4 나 justifies eliding the refcount pair around a borrowed field read (check(node.left)) with "the outer object is owned, the slot is not written meanwhile, no user code runs, and other threads cannot see the gap because of the GIL". It also says the free-threaded build is out of scope because the module re-enables the GIL.

Both no longer hold: the interpreter is free-threaded CPython 3.15t only, with no GIL. Another thread can write the slot and free the child between the borrowed read and its use, so the borrowed pointer can dangle.

Fix (maintainer decision D5, 2026-10-05)

  • Borrowed field reads and refcount elision apply only to objects proven thread-local (never escaped to a global, a container, another thread or unknown code).
  • Every other field read takes a real reference, or reads under CPython's per-object critical section (Py_BEGIN_CRITICAL_SECTION) when a sequence of reads must be consistent.
  • Measurement (ownership investigation): a refcount pair costs about 3.2 ns on an object owned by the current thread and about 14.2 ns on one made by another thread on 3.15t, so the thread-local restriction keeps most of the gain.

Done when

The design text is corrected (with the ownership-inference section), SPEC N-12 states the thread-local condition, and when N-12 is implemented, a free-threaded stress test (one thread reading node.left, another replacing it) passes under ASan/TSan. Related: #159 (FT-safe code generation).

Activity

  1. b-re-w commented on Oct 17, 2026

    @b-re-w
    MemberAuthor

    SPEC N-12 now states the thread-local condition (#198); the design text already did. Stays open for the FT stress test under ASan/TSan with the N-12 implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions