Skip to content

Commit e50e653

Browse files
committed
protect ob_exports atomically
1 parent 4d5bb3a commit e50e653

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

Modules/arraymodule.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ typedef struct {
6969
PyObject *str_iter;
7070
} array_state;
7171

72+
static inline Py_ssize_t Pyarrayobject_GET_SIZE(PyObject *op) {
73+
arrayobject *ao = (arrayobject *)op;
74+
#ifdef Py_GIL_DISABLED
75+
return _Py_atomic_load_ssize_relaxed(&(_PyVarObject_CAST(ao)->ob_size));
76+
#else
77+
return Py_SIZE(ao);
78+
#endif
79+
}
80+
#define Pyarrayobject_GET_SIZE(op) Pyarrayobject_GET_SIZE(_PyObject_CAST(op))
81+
7282
/* Forward declaration. */
7383
static PyObject *array_array_frombytes(PyObject *self, PyObject *bytes);
7484

@@ -137,7 +147,8 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
137147
char *items;
138148
size_t _new_size;
139149

140-
if (self->ob_exports > 0 && newsize != Py_SIZE(self)) {
150+
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_exports) > 0 &&
151+
newsize != Py_SIZE(self)) {
141152
PyErr_SetString(PyExc_BufferError,
142153
"cannot resize an array that is exporting buffers");
143154
return -1;
@@ -728,7 +739,7 @@ array_dealloc(arrayobject *op)
728739
PyTypeObject *tp = Py_TYPE(op);
729740
PyObject_GC_UnTrack(op);
730741

731-
if (op->ob_exports > 0) {
742+
if (FT_ATOMIC_LOAD_SSIZE_RELAXED(op->ob_exports) > 0) {
732743
PyErr_SetString(PyExc_SystemError,
733744
"deallocated array object has exported buffers");
734745
PyErr_Print();
@@ -868,11 +879,7 @@ array_richcompare(PyObject *v, PyObject *w, int op)
868879
static Py_ssize_t
869880
array_length(arrayobject *a)
870881
{
871-
Py_ssize_t ret;
872-
Py_BEGIN_CRITICAL_SECTION(a); // overkill but lets not tempt tsan
873-
ret = Py_SIZE(a);
874-
Py_END_CRITICAL_SECTION();
875-
return ret;
882+
return Pyarrayobject_GET_SIZE(a);
876883
}
877884

878885
static PyObject *
@@ -1074,7 +1081,7 @@ array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
10741081
/* Issue #4509: If the array has exported buffers and the slice
10751082
assignment would change the size of the array, fail early to make
10761083
sure we don't modify it. */
1077-
if (d != 0 && a->ob_exports > 0) {
1084+
if (d != 0 && FT_ATOMIC_LOAD_SSIZE_RELAXED(a->ob_exports) > 0) {
10781085
PyErr_SetString(PyExc_BufferError,
10791086
"cannot resize an array that is exporting buffers");
10801087
return -1;
@@ -2707,7 +2714,8 @@ array_ass_subscr_lock_held(arrayobject* self, PyObject* item, PyObject* value)
27072714
/* Issue #4509: If the array has exported buffers and the slice
27082715
assignment would change the size of the array, fail early to make
27092716
sure we don't modify it. */
2710-
if ((needed == 0 || slicelength != needed) && self->ob_exports > 0) {
2717+
if ((needed == 0 || slicelength != needed) &&
2718+
FT_ATOMIC_LOAD_SSIZE_RELAXED(self->ob_exports) > 0) {
27112719
PyErr_SetString(PyExc_BufferError,
27122720
"cannot resize an array that is exporting buffers");
27132721
return -1;
@@ -2809,6 +2817,7 @@ static const void *emptybuf = "";
28092817
static int
28102818
array_buffer_getbuf_lock_held(arrayobject *self, Py_buffer *view, int flags)
28112819
{
2820+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
28122821
if (view == NULL) {
28132822
PyErr_SetString(PyExc_BufferError,
28142823
"array_buffer_getbuf: view==NULL argument is obsolete");
@@ -2842,7 +2851,11 @@ array_buffer_getbuf_lock_held(arrayobject *self, Py_buffer *view, int flags)
28422851
#endif
28432852
}
28442853

2854+
#ifdef Py_GIL_DISABLED
2855+
_Py_atomic_add_ssize(&self->ob_exports, 1);
2856+
#else
28452857
self->ob_exports++;
2858+
#endif
28462859
return 0;
28472860
}
28482861

@@ -2859,10 +2872,12 @@ array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags)
28592872
static void
28602873
array_buffer_relbuf(arrayobject *self, Py_buffer *view)
28612874
{
2862-
Py_BEGIN_CRITICAL_SECTION(self);
2875+
#ifdef Py_GIL_DISABLED
2876+
assert(_Py_atomic_add_ssize(&self->ob_exports, -1) >= 1);
2877+
#else
28632878
self->ob_exports--;
28642879
assert(self->ob_exports >= 0);
2865-
Py_END_CRITICAL_SECTION();
2880+
#endif
28662881
}
28672882

28682883
static PyObject *
@@ -3315,13 +3330,7 @@ array_arrayiterator___setstate__(arrayiterobject *self, PyObject *state)
33153330
index = -1;
33163331
}
33173332
else {
3318-
Py_ssize_t size;
3319-
#ifdef Py_GIL_DISABLED
3320-
size = _Py_atomic_load_ssize_relaxed(
3321-
&(_PyVarObject_CAST(self->ao)->ob_size));
3322-
#else
3323-
size = Py_SIZE(self->ao);
3324-
#endif
3333+
Py_ssize_t size = Pyarrayobject_GET_SIZE(self->ao);
33253334
if (index > size) {
33263335
index = size; /* iterator at end */
33273336
}

0 commit comments

Comments
 (0)