Skip to content

Commit 287db96

Browse files
corona10aisk
authored andcommitted
pythongh-112087: Make PyList_{Append,Size,GetSlice} to be thread-safe (pythongh-114651)
1 parent 3582acb commit 287db96

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

Include/internal/pycore_list.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ extern void _PyList_Fini(_PyFreeListState *);
2424
extern int
2525
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem);
2626

27+
// In free-threaded build: self should be locked by the caller, if it should be thread-safe.
2728
static inline int
2829
_PyList_AppendTakeRef(PyListObject *self, PyObject *newitem)
2930
{
3031
assert(self != NULL && newitem != NULL);
3132
assert(PyList_Check(self));
32-
Py_ssize_t len = PyList_GET_SIZE(self);
33+
Py_ssize_t len = Py_SIZE(self);
3334
Py_ssize_t allocated = self->allocated;
3435
assert((size_t)len + 1 < PY_SSIZE_T_MAX);
3536
if (allocated > len) {

Include/object.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,11 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
428428
static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
429429
assert(ob->ob_base.ob_type != &PyLong_Type);
430430
assert(ob->ob_base.ob_type != &PyBool_Type);
431+
#ifdef Py_GIL_DISABLED
432+
_Py_atomic_store_ssize_relaxed(&ob->ob_size, size);
433+
#else
431434
ob->ob_size = size;
435+
#endif
432436
}
433437
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
434438
# define Py_SET_SIZE(ob, size) Py_SET_SIZE(_PyVarObject_CAST(ob), (size))

Objects/listobject.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ get_list_state(void)
3030
}
3131
#endif
3232

33-
3433
/* Ensure ob_item has room for at least newsize elements, and set
3534
* ob_size to newsize. If newsize > ob_size on entry, the content
3635
* of the new slots at exit is undefined heap trash; it's the caller's
@@ -221,8 +220,9 @@ PyList_Size(PyObject *op)
221220
PyErr_BadInternalCall();
222221
return -1;
223222
}
224-
else
225-
return Py_SIZE(op);
223+
else {
224+
return PyList_GET_SIZE(op);
225+
}
226226
}
227227

228228
static inline int
@@ -328,7 +328,7 @@ PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
328328
int
329329
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
330330
{
331-
Py_ssize_t len = PyList_GET_SIZE(self);
331+
Py_ssize_t len = Py_SIZE(self);
332332
assert(self->allocated == -1 || self->allocated == len);
333333
if (list_resize(self, len + 1) < 0) {
334334
Py_DECREF(newitem);
@@ -342,7 +342,11 @@ int
342342
PyList_Append(PyObject *op, PyObject *newitem)
343343
{
344344
if (PyList_Check(op) && (newitem != NULL)) {
345-
return _PyList_AppendTakeRef((PyListObject *)op, Py_NewRef(newitem));
345+
int ret;
346+
Py_BEGIN_CRITICAL_SECTION(op);
347+
ret = _PyList_AppendTakeRef((PyListObject *)op, Py_NewRef(newitem));
348+
Py_END_CRITICAL_SECTION();
349+
return ret;
346350
}
347351
PyErr_BadInternalCall();
348352
return -1;
@@ -473,7 +477,7 @@ static PyObject *
473477
list_item(PyObject *aa, Py_ssize_t i)
474478
{
475479
PyListObject *a = (PyListObject *)aa;
476-
if (!valid_index(i, Py_SIZE(a))) {
480+
if (!valid_index(i, PyList_GET_SIZE(a))) {
477481
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
478482
return NULL;
479483
}
@@ -511,6 +515,8 @@ PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
511515
PyErr_BadInternalCall();
512516
return NULL;
513517
}
518+
PyObject *ret;
519+
Py_BEGIN_CRITICAL_SECTION(a);
514520
if (ilow < 0) {
515521
ilow = 0;
516522
}
@@ -523,7 +529,9 @@ PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
523529
else if (ihigh > Py_SIZE(a)) {
524530
ihigh = Py_SIZE(a);
525531
}
526-
return list_slice((PyListObject *)a, ilow, ihigh);
532+
ret = list_slice((PyListObject *)a, ilow, ihigh);
533+
Py_END_CRITICAL_SECTION();
534+
return ret;
527535
}
528536

529537
static PyObject *

0 commit comments

Comments
 (0)