From 841fed6d5a5468067a644e1827130f21a311ab1e Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 15 May 2026 15:38:51 +0300 Subject: [PATCH] [3.13] gh-149816: Fix race condition in `memoryview` with free-threading (GH-149858) (cherry picked from commit 1fdf0337742762cc47837042747cc607f024a202) Co-authored-by: sobolevn --- ...-05-15-11-31-57.gh-issue-149816.ugN2rx.rst | 1 + Objects/memoryobject.c | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst new file mode 100644 index 00000000000000..016c17dd66b19e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-15-11-31-57.gh-issue-149816.ugN2rx.rst @@ -0,0 +1 @@ +Fix a race condition in :class:`memoryview` with free-threading. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index b361d64d34d674..82ae47c334cc31 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -67,6 +67,13 @@ class memoryview "PyMemoryViewObject *" "&PyMemoryView_Type" releasebufferprocs must NOT decrement view.obj. */ +#ifdef Py_GIL_DISABLED + #define _FT_ATOMIC_ADD_SSIZE(value, new_value) \ + (void)_Py_atomic_add_ssize(&value, new_value) +#else + #define _FT_ATOMIC_ADD_SSIZE(value, new_value) (void)(value += new_value) +#endif + static inline _PyManagedBufferObject * mbuf_alloc(void) @@ -1589,7 +1596,7 @@ memory_getbuf(PyObject *_self, Py_buffer *view, int flags) view->obj = Py_NewRef(self); - self->exports++; + _FT_ATOMIC_ADD_SSIZE(self->exports, 1); return 0; } @@ -1598,7 +1605,7 @@ static void memory_releasebuf(PyObject *_self, Py_buffer *view) { PyMemoryViewObject *self = (PyMemoryViewObject *)_self; - self->exports--; + _FT_ATOMIC_ADD_SSIZE(self->exports, -1); return; /* PyBuffer_Release() decrements view->obj after this function returns. */ } @@ -2337,9 +2344,9 @@ memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep, // Prevent 'self' from being freed if computing len(sep) mutates 'self' // in _Py_strhex_with_sep(). // See: https://github.com/python/cpython/issues/143195. - self->exports++; + _FT_ATOMIC_ADD_SSIZE(self->exports, 1); PyObject *ret = _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep); - self->exports--; + _FT_ATOMIC_ADD_SSIZE(self->exports, -1); return ret; } @@ -3081,9 +3088,9 @@ memory_hash(PyObject *_self) if (view->obj != NULL) { // Prevent 'self' from being freed when computing the item's hash. // See https://github.com/python/cpython/issues/142664. - self->exports++; + _FT_ATOMIC_ADD_SSIZE(self->exports, 1); Py_hash_t h = PyObject_Hash(view->obj); - self->exports--; + _FT_ATOMIC_ADD_SSIZE(self->exports, -1); if (h == -1) { /* Keep the original error message */ return -1; @@ -3457,3 +3464,5 @@ PyTypeObject PyMemoryView_Type = { 0, /* tp_alloc */ memoryview, /* tp_new */ }; + +#undef _FT_ATOMIC_ADD_SSIZE