Skip to content

Commit e51da64

Browse files
authored
gh-127536: Add missing locks in listobject.c (GH-127580)
We were missing locks around some list operations in the free threading build.
1 parent 51cfa56 commit e51da64

File tree

2 files changed

+42
-10
lines changed

2 files changed

+42
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add missing locks around some list assignment operations in the free
2+
threading build.

Objects/listobject.c

+40-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "Python.h"
44
#include "pycore_abstract.h" // _PyIndex_Check()
55
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
6+
#include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED()
67
#include "pycore_dict.h" // _PyDictViewObject
78
#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
89
#include "pycore_pyatomic_ft_wrappers.h"
@@ -72,6 +73,11 @@ static void
7273
ensure_shared_on_resize(PyListObject *self)
7374
{
7475
#ifdef Py_GIL_DISABLED
76+
// We can't use _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED here because
77+
// the `CALL_LIST_APPEND` bytecode handler may lock the list without
78+
// a critical section.
79+
assert(Py_REFCNT(self) == 1 || PyMutex_IsLocked(&_PyObject_CAST(self)->ob_mutex));
80+
7581
// Ensure that the list array is freed using QSBR if we are not the
7682
// owning thread.
7783
if (!_Py_IsOwnedByCurrentThread((PyObject *)self) &&
@@ -957,10 +963,12 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
957963
Py_ssize_t n = PyList_GET_SIZE(a);
958964
PyObject *copy = list_slice_lock_held(a, 0, n);
959965
if (copy == NULL) {
960-
return -1;
966+
ret = -1;
967+
}
968+
else {
969+
ret = list_ass_slice_lock_held(a, ilow, ihigh, copy);
970+
Py_DECREF(copy);
961971
}
962-
ret = list_ass_slice_lock_held(a, ilow, ihigh, copy);
963-
Py_DECREF(copy);
964972
Py_END_CRITICAL_SECTION();
965973
}
966974
else if (v != NULL && PyList_CheckExact(v)) {
@@ -1437,7 +1445,9 @@ PyList_Clear(PyObject *self)
14371445
PyErr_BadInternalCall();
14381446
return -1;
14391447
}
1448+
Py_BEGIN_CRITICAL_SECTION(self);
14401449
list_clear((PyListObject*)self);
1450+
Py_END_CRITICAL_SECTION();
14411451
return 0;
14421452
}
14431453

@@ -3410,7 +3420,9 @@ list___init___impl(PyListObject *self, PyObject *iterable)
34103420

34113421
/* Empty previous contents */
34123422
if (self->ob_item != NULL) {
3423+
Py_BEGIN_CRITICAL_SECTION(self);
34133424
list_clear(self);
3425+
Py_END_CRITICAL_SECTION();
34143426
}
34153427
if (iterable != NULL) {
34163428
if (_list_extend(self, iterable) < 0) {
@@ -3583,16 +3595,18 @@ adjust_slice_indexes(PyListObject *lst,
35833595
}
35843596

35853597
static int
3586-
list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
3598+
list_ass_subscript_lock_held(PyObject *_self, PyObject *item, PyObject *value)
35873599
{
3600+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(_self);
3601+
35883602
PyListObject *self = (PyListObject *)_self;
35893603
if (_PyIndex_Check(item)) {
35903604
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
35913605
if (i == -1 && PyErr_Occurred())
35923606
return -1;
35933607
if (i < 0)
35943608
i += PyList_GET_SIZE(self);
3595-
return list_ass_item((PyObject *)self, i, value);
3609+
return list_ass_item_lock_held(self, i, value);
35963610
}
35973611
else if (PySlice_Check(item)) {
35983612
Py_ssize_t start, stop, step;
@@ -3612,7 +3626,7 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
36123626
step);
36133627

36143628
if (step == 1)
3615-
return list_ass_slice(self, start, stop, value);
3629+
return list_ass_slice_lock_held(self, start, stop, value);
36163630

36173631
if (slicelength <= 0)
36183632
return 0;
@@ -3678,10 +3692,8 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
36783692

36793693
/* protect against a[::-1] = a */
36803694
if (self == (PyListObject*)value) {
3681-
Py_BEGIN_CRITICAL_SECTION(value);
3682-
seq = list_slice_lock_held((PyListObject*)value, 0,
3695+
seq = list_slice_lock_held((PyListObject *)value, 0,
36833696
Py_SIZE(value));
3684-
Py_END_CRITICAL_SECTION();
36853697
}
36863698
else {
36873699
seq = PySequence_Fast(value,
@@ -3695,7 +3707,7 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
36953707
step);
36963708

36973709
if (step == 1) {
3698-
int res = list_ass_slice(self, start, stop, seq);
3710+
int res = list_ass_slice_lock_held(self, start, stop, seq);
36993711
Py_DECREF(seq);
37003712
return res;
37013713
}
@@ -3751,6 +3763,24 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
37513763
}
37523764
}
37533765

3766+
static int
3767+
list_ass_subscript(PyObject *self, PyObject *item, PyObject *value)
3768+
{
3769+
int res;
3770+
#ifdef Py_GIL_DISABLED
3771+
if (PySlice_Check(item) && value != NULL && PyList_CheckExact(value)) {
3772+
Py_BEGIN_CRITICAL_SECTION2(self, value);
3773+
res = list_ass_subscript_lock_held(self, item, value);
3774+
Py_END_CRITICAL_SECTION2();
3775+
return res;
3776+
}
3777+
#endif
3778+
Py_BEGIN_CRITICAL_SECTION(self);
3779+
res = list_ass_subscript_lock_held(self, item, value);
3780+
Py_END_CRITICAL_SECTION();
3781+
return res;
3782+
}
3783+
37543784
static PyMappingMethods list_as_mapping = {
37553785
list_length,
37563786
list_subscript,

0 commit comments

Comments
 (0)