Description
Bug report
Seen in https://github.com/python/cpython/actions/runs/12216713951/job/34310688405?pr=126865:
Reported by @markshannon
==================
WARNING: ThreadSanitizer: data race (pid=20210)
Write of size 8 at 0x7fbb3e0415f0 by thread T31:
#0 _PyFreeList_Push /home/runner/work/cpython/cpython/./Include/internal/pycore_freelist.h:54:23 (python+0x2cbe10) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#1 _PyFreeList_Free /home/runner/work/cpython/cpython/./Include/internal/pycore_freelist.h:67:10 (python+0x2cbe10)
#2 long_dealloc /home/runner/work/cpython/cpython/Objects/longobject.c:3667:[13](https://github.com/python/cpython/actions/runs/12216713951/job/34310688405?pr=126865#step:13:14) (python+0x2cbe10)
#3 _Py_Dealloc /home/runner/work/cpython/cpython/Objects/object.c:2977:5 (python+0x3186c4) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#4 _Py_MergeZeroLocalRefcount /home/runner/work/cpython/cpython/Objects/object.c (python+0x318d15) (BuildId: 7dc38[14](https://github.com/python/cpython/actions/runs/12216713951/job/34310688405?pr=126865#step:13:15)d1a5683dfc5de7e8c3c8846a47a478499)
#5 Py_DECREF /home/runner/work/cpython/cpython/./Include/refcount.h:323:13 (python+0x5ea28e) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#6 Py_XDECREF /home/runner/work/cpython/cpython/./Include/refcount.h:476:9 (python+0x5ea28e)
#7 PyMember_SetOne /home/runner/work/cpython/cpython/Python/structmember.c:315:9
...
Previous atomic read of size 8 at 0x7fbb3e0415f0 by thread T32:
#0 _Py_atomic_load_uintptr_relaxed /home/runner/work/cpython/cpython/./Include/cpython/pyatomic_gcc.h:375:10 (python+0x5e96b9) (BuildId: 7dc[38](https://github.com/python/cpython/actions/runs/12216713951/job/34310688405?pr=126865#step:13:39)14d1a5683dfc5de7e8c3c8846a47a478499)
#1 _Py_IsOwnedByCurrentThread /home/runner/work/cpython/cpython/./Include/object.h:242:12 (python+0x5e96b9)
#2 _Py_TryIncrefFast /home/runner/work/cpython/cpython/./Include/internal/pycore_object.h:547:9 (python+0x5e96b9)
#3 _Py_TryIncrefCompare /home/runner/work/cpython/cpython/./Include/internal/pycore_object.h:586:9 (python+0x5e96b9)
#4 PyMember_GetOne /home/runner/work/cpython/cpython/Python/structmember.c:99:18 (python+0x5e93d5) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#5 member_get /home/runner/work/cpython/cpython/Objects/descrobject.c:179:12 (python+0x268c59) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#6 _PyObject_GenericGetAttrWithDict /home/runner/work/cpython/cpython/Objects/object.c:1690:19 (python+0x31d32b) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#7 PyObject_GenericGetAttr /home/runner/work/cpython/cpython/Objects/object.c:1772:12 (python+0x31d1[44](https://github.com/python/cpython/actions/runs/12216713951/job/34310688405?pr=126865#step:13:45)) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#8 PyObject_GetAttr /home/runner/work/cpython/cpython/Objects/object.c:1286:18 (python+0x31c6da) (BuildId: 7dc3814d1a5683dfc5de7e8c3c8846a47a478499)
#9 _PyEval_EvalFrameDefault /home/runner/work/cpython/cpython/Python/generated_cases.c.h:5254:30 (python+0x4da626) (BuildId: 7dc3814d1a5683dfc5de7e8c3c88
We should be using a relaxed atomic write in pycore_freelist.h.
The background is that we have a few places (dict, list, structmember) that have a fast-path that attempts to avoid a lock. (https://peps.python.org/pep-0703/#optimistically-avoiding-locking). They may access the ob_tid and refcount fields while the object is freed (but the memory is still valid).
The freelist overwrites the first field (ob_tid in the free threading build). That's okay semantically because valid pointers are distinct from the thread ids we use for ob_tid (the GC also relies on this property). However, we still need to use an atomic operation (relaxed is fine here) when we write the field.