Skip to content

Commit 1677fb3

Browse files
committed
gh-127716: Fix data race in memoryview.release()
1 parent 993a0c6 commit 1677fb3

1 file changed

Lines changed: 23 additions & 7 deletions

File tree

Objects/memoryobject.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,25 @@ _PyManagedBuffer_FromObject(PyObject *base, int flags)
103103
return (PyObject *)mbuf;
104104
}
105105

106+
static inline int
107+
atomic_or(int *flags, int bit)
108+
{
109+
#ifdef Py_GIL_DISABLED
110+
return (int)_Py_atomic_or_uint32((uint32_t *)flags, (uint32_t)bit);
111+
#else
112+
int prev = *flags;
113+
*flags = prev | bit;
114+
return prev;
115+
#endif
116+
}
117+
106118
static void
107119
mbuf_release(_PyManagedBufferObject *self)
108120
{
109-
if (self->flags&_Py_MANAGED_BUFFER_RELEASED)
121+
int prev_flags = atomic_or(&self->flags, _Py_MANAGED_BUFFER_RELEASED);
122+
if (prev_flags & _Py_MANAGED_BUFFER_RELEASED)
110123
return;
111124

112-
self->flags |= _Py_MANAGED_BUFFER_RELEASED;
113-
114125
/* PyBuffer_Release() decrements master->obj and sets it to NULL. */
115126
_PyObject_GC_UNTRACK(self);
116127
PyBuffer_Release(&self->master);
@@ -1109,12 +1120,17 @@ static void
11091120
_memory_release(PyMemoryViewObject *self)
11101121
{
11111122
assert(get_exports(self) == 0);
1112-
if (self->flags & _Py_MEMORYVIEW_RELEASED)
1123+
int prev_flags = atomic_or(&self->flags, _Py_MEMORYVIEW_RELEASED);
1124+
if (prev_flags & _Py_MEMORYVIEW_RELEASED)
11131125
return;
11141126

1115-
self->flags |= _Py_MEMORYVIEW_RELEASED;
1116-
assert(self->mbuf->exports > 0);
1117-
if (--self->mbuf->exports == 0) {
1127+
#ifdef Py_GIL_DISABLED
1128+
Py_ssize_t prev_exports = _Py_atomic_add_ssize(&self->mbuf->exports, -1);
1129+
#else
1130+
Py_ssize_t prev_exports = self->mbuf->exports--;
1131+
#endif
1132+
assert(prev_exports > 0);
1133+
if (prev_exports == 1) {
11181134
mbuf_release(self->mbuf);
11191135
}
11201136
}

0 commit comments

Comments
 (0)