Skip to content

Commit 6cddc73

Browse files
authored
gh-112087: Make list_{slice, ass_slice, subscript} to be threadsafe (gh-116233)
1 parent 58c7919 commit 6cddc73

File tree

2 files changed

+87
-50
lines changed

2 files changed

+87
-50
lines changed

Lib/test/test_list.py

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ def imul(a, b): a *= b
9696
self.assertRaises((MemoryError, OverflowError), mul, lst, n)
9797
self.assertRaises((MemoryError, OverflowError), imul, lst, n)
9898

99+
def test_empty_slice(self):
100+
x = []
101+
x[:] = x
102+
self.assertEqual(x, [])
103+
99104
def test_list_resize_overflow(self):
100105
# gh-97616: test new_allocated * sizeof(PyObject*) overflow
101106
# check in list_resize()

Objects/listobject.c

+82-50
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ list_item(PyObject *aa, Py_ssize_t i)
515515
}
516516

517517
static PyObject *
518-
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
518+
list_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
519519
{
520520
PyListObject *np;
521521
PyObject **src, **dest;
@@ -559,7 +559,7 @@ PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
559559
else if (ihigh > Py_SIZE(a)) {
560560
ihigh = Py_SIZE(a);
561561
}
562-
ret = list_slice((PyListObject *)a, ilow, ihigh);
562+
ret = list_slice_lock_held((PyListObject *)a, ilow, ihigh);
563563
Py_END_CRITICAL_SECTION();
564564
return ret;
565565
}
@@ -584,13 +584,13 @@ list_concat_lock_held(PyListObject *a, PyListObject *b)
584584
dest = np->ob_item;
585585
for (i = 0; i < Py_SIZE(a); i++) {
586586
PyObject *v = src[i];
587-
FT_ATOMIC_STORE_PTR_RELAXED(dest[i], Py_NewRef(v));
587+
dest[i] = Py_NewRef(v);
588588
}
589589
src = b->ob_item;
590590
dest = np->ob_item + Py_SIZE(a);
591591
for (i = 0; i < Py_SIZE(b); i++) {
592592
PyObject *v = src[i];
593-
FT_ATOMIC_STORE_PTR_RELAXED(dest[i], Py_NewRef(v));
593+
dest[i] = Py_NewRef(v);
594594
}
595595
Py_SET_SIZE(np, size);
596596
return (PyObject *)np;
@@ -636,15 +636,15 @@ list_repeat_lock_held(PyListObject *a, Py_ssize_t n)
636636
_Py_RefcntAdd(elem, n);
637637
PyObject **dest_end = dest + output_size;
638638
while (dest < dest_end) {
639-
FT_ATOMIC_STORE_PTR_RELAXED(*dest++, elem);
639+
*dest++ = elem;
640640
}
641641
}
642642
else {
643643
PyObject **src = a->ob_item;
644644
PyObject **src_end = src + input_size;
645645
while (src < src_end) {
646646
_Py_RefcntAdd(*src, n);
647-
FT_ATOMIC_STORE_PTR_RELAXED(*dest++, *src++);
647+
*dest++ = *src++;
648648
}
649649

650650
_Py_memory_repeat((char *)np->ob_item, sizeof(PyObject *)*output_size,
@@ -718,7 +718,7 @@ list_clear_slot(PyObject *self)
718718
* guaranteed the call cannot fail.
719719
*/
720720
static int
721-
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
721+
list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
722722
{
723723
/* Because [X]DECREF can recursively invoke list operations on
724724
this list, we must postpone all [X]DECREF activity until
@@ -741,15 +741,6 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
741741
if (v == NULL)
742742
n = 0;
743743
else {
744-
if (a == b) {
745-
/* Special case "a[i:j] = a" -- copy b first */
746-
v = list_slice(b, 0, Py_SIZE(b));
747-
if (v == NULL)
748-
return result;
749-
result = list_ass_slice(a, ilow, ihigh, v);
750-
Py_DECREF(v);
751-
return result;
752-
}
753744
v_as_SF = PySequence_Fast(v, "can only assign an iterable");
754745
if(v_as_SF == NULL)
755746
goto Error;
@@ -823,6 +814,34 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
823814
#undef b
824815
}
825816

817+
static int
818+
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
819+
{
820+
int ret;
821+
if (a == (PyListObject *)v) {
822+
Py_BEGIN_CRITICAL_SECTION(a);
823+
Py_ssize_t n = PyList_GET_SIZE(a);
824+
PyObject *copy = list_slice_lock_held(a, 0, n);
825+
if (copy == NULL) {
826+
return -1;
827+
}
828+
ret = list_ass_slice_lock_held(a, ilow, ihigh, copy);
829+
Py_DECREF(copy);
830+
Py_END_CRITICAL_SECTION();
831+
}
832+
else if (v != NULL && PyList_CheckExact(v)) {
833+
Py_BEGIN_CRITICAL_SECTION2(a, v);
834+
ret = list_ass_slice_lock_held(a, ilow, ihigh, v);
835+
Py_END_CRITICAL_SECTION2();
836+
}
837+
else {
838+
Py_BEGIN_CRITICAL_SECTION(a);
839+
ret = list_ass_slice_lock_held(a, ilow, ihigh, v);
840+
Py_END_CRITICAL_SECTION();
841+
}
842+
return ret;
843+
}
844+
826845
int
827846
PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
828847
{
@@ -956,7 +975,7 @@ static PyObject *
956975
list_copy_impl(PyListObject *self)
957976
/*[clinic end generated code: output=ec6b72d6209d418e input=81c54b0c7bb4f73d]*/
958977
{
959-
return list_slice(self, 0, Py_SIZE(self));
978+
return list_slice_lock_held(self, 0, Py_SIZE(self));
960979
}
961980

962981
/*[clinic input]
@@ -2884,8 +2903,7 @@ list_remove_impl(PyListObject *self, PyObject *value)
28842903
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
28852904
Py_DECREF(obj);
28862905
if (cmp > 0) {
2887-
if (list_ass_slice(self, i, i+1,
2888-
(PyObject *)NULL) == 0)
2906+
if (list_ass_slice_lock_held(self, i, i+1, NULL) == 0)
28892907
Py_RETURN_NONE;
28902908
return NULL;
28912909
}
@@ -3085,6 +3103,45 @@ static PySequenceMethods list_as_sequence = {
30853103
list_inplace_repeat, /* sq_inplace_repeat */
30863104
};
30873105

3106+
static inline PyObject *
3107+
list_slice_step_lock_held(PyListObject *a, Py_ssize_t start, Py_ssize_t step, Py_ssize_t len)
3108+
{
3109+
PyListObject *np = (PyListObject *)list_new_prealloc(len);
3110+
if (np == NULL) {
3111+
return NULL;
3112+
}
3113+
size_t cur;
3114+
Py_ssize_t i;
3115+
PyObject **src = a->ob_item;
3116+
PyObject **dest = np->ob_item;
3117+
for (cur = start, i = 0; i < len;
3118+
cur += (size_t)step, i++) {
3119+
PyObject *v = src[cur];
3120+
dest[i] = Py_NewRef(v);
3121+
}
3122+
Py_SET_SIZE(np, len);
3123+
return (PyObject *)np;
3124+
}
3125+
3126+
static PyObject *
3127+
list_slice_wrap(PyListObject *aa, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step)
3128+
{
3129+
PyObject *res = NULL;
3130+
Py_BEGIN_CRITICAL_SECTION(aa);
3131+
Py_ssize_t len = PySlice_AdjustIndices(Py_SIZE(aa), &start, &stop, step);
3132+
if (len <= 0) {
3133+
res = PyList_New(0);
3134+
}
3135+
else if (step == 1) {
3136+
res = list_slice_lock_held(aa, start, stop);
3137+
}
3138+
else {
3139+
res = list_slice_step_lock_held(aa, start, step, len);
3140+
}
3141+
Py_END_CRITICAL_SECTION();
3142+
return res;
3143+
}
3144+
30883145
static PyObject *
30893146
list_subscript(PyObject* _self, PyObject* item)
30903147
{
@@ -3099,38 +3156,11 @@ list_subscript(PyObject* _self, PyObject* item)
30993156
return list_item((PyObject *)self, i);
31003157
}
31013158
else if (PySlice_Check(item)) {
3102-
Py_ssize_t start, stop, step, slicelength, i;
3103-
size_t cur;
3104-
PyObject* result;
3105-
PyObject* it;
3106-
PyObject **src, **dest;
3107-
3159+
Py_ssize_t start, stop, step;
31083160
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
31093161
return NULL;
31103162
}
3111-
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
3112-
step);
3113-
3114-
if (slicelength <= 0) {
3115-
return PyList_New(0);
3116-
}
3117-
else if (step == 1) {
3118-
return list_slice(self, start, stop);
3119-
}
3120-
else {
3121-
result = list_new_prealloc(slicelength);
3122-
if (!result) return NULL;
3123-
3124-
src = self->ob_item;
3125-
dest = ((PyListObject *)result)->ob_item;
3126-
for (cur = start, i = 0; i < slicelength;
3127-
cur += (size_t)step, i++) {
3128-
it = Py_NewRef(src[cur]);
3129-
dest[i] = it;
3130-
}
3131-
Py_SET_SIZE(result, slicelength);
3132-
return result;
3133-
}
3163+
return list_slice_wrap(self, start, stop, step);
31343164
}
31353165
else {
31363166
PyErr_Format(PyExc_TypeError,
@@ -3241,8 +3271,10 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
32413271

32423272
/* protect against a[::-1] = a */
32433273
if (self == (PyListObject*)value) {
3244-
seq = list_slice((PyListObject*)value, 0,
3245-
PyList_GET_SIZE(value));
3274+
Py_BEGIN_CRITICAL_SECTION(value);
3275+
seq = list_slice_lock_held((PyListObject*)value, 0,
3276+
Py_SIZE(value));
3277+
Py_END_CRITICAL_SECTION();
32463278
}
32473279
else {
32483280
seq = PySequence_Fast(value,

0 commit comments

Comments
 (0)