Skip to content

Commit 8334a1b

Browse files
authored
gh-120384: Fix array-out-of-bounds crash in list_ass_subscript (#120442)
1 parent 733dac0 commit 8334a1b

File tree

4 files changed

+58
-12
lines changed

4 files changed

+58
-12
lines changed

Lib/test/list_tests.py

+8
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,14 @@ def test_setslice(self):
191191

192192
self.assertRaises(TypeError, a.__setitem__)
193193

194+
def test_slice_assign_iterator(self):
195+
x = self.type2test(range(5))
196+
x[0:3] = reversed(range(3))
197+
self.assertEqual(x, self.type2test([2, 1, 0, 3, 4]))
198+
199+
x[:] = reversed(range(3))
200+
self.assertEqual(x, self.type2test([2, 1, 0]))
201+
194202
def test_delslice(self):
195203
a = self.type2test([0, 1])
196204
del a[1:2]

Lib/test/test_list.py

+14
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ def __lt__(self, other):
245245
with self.assertRaises(TypeError):
246246
a[0] < a
247247

248+
def test_list_index_modifing_operand(self):
249+
# See gh-120384
250+
class evil:
251+
def __init__(self, lst):
252+
self.lst = lst
253+
def __iter__(self):
254+
yield from self.lst
255+
self.lst.clear()
256+
257+
lst = list(range(5))
258+
operand = evil(lst)
259+
with self.assertRaises(ValueError):
260+
lst[::-1] = operand
261+
248262
@cpython_only
249263
def test_preallocation(self):
250264
iterable = [0] * 10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an array out of bounds crash in ``list_ass_subscript``, which could be
2+
invoked via some specificly tailored input: including concurrent modification
3+
of a list object, where one thread assigns a slice and another clears it.

Objects/listobject.c

+33-12
Original file line numberDiff line numberDiff line change
@@ -3581,6 +3581,23 @@ list_subscript(PyObject* _self, PyObject* item)
35813581
}
35823582
}
35833583

3584+
static Py_ssize_t
3585+
adjust_slice_indexes(PyListObject *lst,
3586+
Py_ssize_t *start, Py_ssize_t *stop,
3587+
Py_ssize_t step)
3588+
{
3589+
Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop,
3590+
step);
3591+
3592+
/* Make sure s[5:2] = [..] inserts at the right place:
3593+
before 5, not before 2. */
3594+
if ((step < 0 && *start < *stop) ||
3595+
(step > 0 && *start > *stop))
3596+
*stop = *start;
3597+
3598+
return slicelength;
3599+
}
3600+
35843601
static int
35853602
list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
35863603
{
@@ -3594,22 +3611,11 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
35943611
return list_ass_item((PyObject *)self, i, value);
35953612
}
35963613
else if (PySlice_Check(item)) {
3597-
Py_ssize_t start, stop, step, slicelength;
3614+
Py_ssize_t start, stop, step;
35983615

35993616
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
36003617
return -1;
36013618
}
3602-
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
3603-
step);
3604-
3605-
if (step == 1)
3606-
return list_ass_slice(self, start, stop, value);
3607-
3608-
/* Make sure s[5:2] = [..] inserts at the right place:
3609-
before 5, not before 2. */
3610-
if ((step < 0 && start < stop) ||
3611-
(step > 0 && start > stop))
3612-
stop = start;
36133619

36143620
if (value == NULL) {
36153621
/* delete slice */
@@ -3618,6 +3624,12 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
36183624
Py_ssize_t i;
36193625
int res;
36203626

3627+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
3628+
step);
3629+
3630+
if (step == 1)
3631+
return list_ass_slice(self, start, stop, value);
3632+
36213633
if (slicelength <= 0)
36223634
return 0;
36233635

@@ -3695,6 +3707,15 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
36953707
if (!seq)
36963708
return -1;
36973709

3710+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
3711+
step);
3712+
3713+
if (step == 1) {
3714+
int res = list_ass_slice(self, start, stop, seq);
3715+
Py_DECREF(seq);
3716+
return res;
3717+
}
3718+
36983719
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
36993720
PyErr_Format(PyExc_ValueError,
37003721
"attempt to assign sequence of "

0 commit comments

Comments
 (0)