◐ Shell
clean mode source ↗

gh-149816: Fix race in subtype_getweakref in free-threading build by Abhi210 · Pull Request #150247 · python/cpython

This PR resolves finding 61 from the weakref race tracking issue: "Racy weakref head load before incref in Objects/typeobject.c".

Description

In free-threaded builds, subtype_getweakref() had a race condition where the weakref list head (*weaklistptr) was loaded and immediately passed to Py_NewRef(). If another thread concurrently triggered weakref_dealloc(), the weakref could be freed before the incref, leading to a use-after-free (UAF).

This PR fixes the issue by:

  1. Wrapping the pointer load and incref sequence inside the existing LOCK_WEAKREFS(obj) / UNLOCK_WEAKREFS(obj) critical section.
  2. Replacing Py_NewRef() with _Py_TryIncref() to safely handle weakrefs whose refcount has reached zero during the race window.
  3. Returning Py_NewRef(Py_None) when the list is empty or the weakref is no longer live, preserving the existing API behavior.

Testing

Added regression tests in Lib/test/test_free_threading/test_weakref.py that:

  • Exercise obj.__weakref__ concurrently from reader and mutator threads synchronized with threading.Barrier.
  • Verify correct return values (None versus weakref.ref).
  • Check refcount stability across repeated accesses to detect leaks or incorrect incref/decref behavior.

AI Tool Disclosure:

Claude Code was used to help understand the relevant code paths and to improve the clarity and documentation of the proposed tests. It was not used to modify Objects/typeobject.c; all code changes and final decisions were made by me.