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:
- Wrapping the pointer load and incref sequence inside the existing
LOCK_WEAKREFS(obj)/UNLOCK_WEAKREFS(obj)critical section. - Replacing
Py_NewRef()with_Py_TryIncref()to safely handle weakrefs whose refcount has reached zero during the race window. - 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 withthreading.Barrier. - Verify correct return values (
Noneversusweakref.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.