From 18d376b5fb5716a10633aff96fe06f292d4766ce Mon Sep 17 00:00:00 2001 From: Matt Page Date: Wed, 24 Apr 2024 16:23:48 -0700 Subject: [PATCH] Fix data race in `_Py_IsImmortal` The load of `ob_ref_local`: https://github.com/python/cpython/blob/4b10e209c76f9f36f8ae2e4d713b3a01591c1856/Include/object.h#L352 races with ([example](https://gist.github.com/mpage/7e2028b3ca811deb350f705bc3c737ca)) stores: https://github.com/python/cpython/blob/4b10e209c76f9f36f8ae2e4d713b3a01591c1856/Include/object.h#L883 Using a relaxed load is sufficient; stores to the field are relaxed. --- Include/object.h | 3 ++- Tools/tsan/suppressions_free_threading.txt | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/object.h b/Include/object.h index ffcacf1a3ef4ed..5aaf11c5194f0e 100644 --- a/Include/object.h +++ b/Include/object.h @@ -349,7 +349,8 @@ static inline Py_ssize_t Py_SIZE(PyObject *ob) { static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op) { #if defined(Py_GIL_DISABLED) - return (op->ob_ref_local == _Py_IMMORTAL_REFCNT_LOCAL); + return (_Py_atomic_load_uint32_relaxed(&op->ob_ref_local) == + _Py_IMMORTAL_REFCNT_LOCAL); #elif SIZEOF_VOID_P > 4 return (_Py_CAST(PY_INT32_T, op->ob_refcnt) < 0); #else diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 1408103ba80f96..6ceb275925c5e1 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -14,7 +14,6 @@ race:set_allocator_unlocked race:_add_to_weak_set race:_in_weak_set race:_mi_heap_delayed_free_partial -race:_Py_IsImmortal race:_Py_IsOwnedByCurrentThread race:_PyEval_EvalFrameDefault race:_PyFunction_SetVersion