0
0
mirror of https://github.com/python/cpython.git synced 2024-11-21 12:59:38 +01:00

gh-120384: Fix array-out-of-bounds crash in list_ass_subscript (#120442)

This commit is contained in:
Nikita Sobolev 2024-06-21 13:48:38 +03:00 committed by GitHub
parent 733dac01b0
commit 8334a1b55c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 12 deletions

View File

@ -191,6 +191,14 @@ class CommonTest(seq_tests.CommonTest):
self.assertRaises(TypeError, a.__setitem__)
def test_slice_assign_iterator(self):
x = self.type2test(range(5))
x[0:3] = reversed(range(3))
self.assertEqual(x, self.type2test([2, 1, 0, 3, 4]))
x[:] = reversed(range(3))
self.assertEqual(x, self.type2test([2, 1, 0]))
def test_delslice(self):
a = self.type2test([0, 1])
del a[1:2]

View File

@ -245,6 +245,20 @@ class ListTest(list_tests.CommonTest):
with self.assertRaises(TypeError):
a[0] < a
def test_list_index_modifing_operand(self):
# See gh-120384
class evil:
def __init__(self, lst):
self.lst = lst
def __iter__(self):
yield from self.lst
self.lst.clear()
lst = list(range(5))
operand = evil(lst)
with self.assertRaises(ValueError):
lst[::-1] = operand
@cpython_only
def test_preallocation(self):
iterable = [0] * 10

View File

@ -0,0 +1,3 @@
Fix an array out of bounds crash in ``list_ass_subscript``, which could be
invoked via some specificly tailored input: including concurrent modification
of a list object, where one thread assigns a slice and another clears it.

View File

@ -3581,6 +3581,23 @@ list_subscript(PyObject* _self, PyObject* item)
}
}
static Py_ssize_t
adjust_slice_indexes(PyListObject *lst,
Py_ssize_t *start, Py_ssize_t *stop,
Py_ssize_t step)
{
Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop,
step);
/* Make sure s[5:2] = [..] inserts at the right place:
before 5, not before 2. */
if ((step < 0 && *start < *stop) ||
(step > 0 && *start > *stop))
*stop = *start;
return slicelength;
}
static int
list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
{
@ -3594,22 +3611,11 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
return list_ass_item((PyObject *)self, i, value);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
Py_ssize_t start, stop, step;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return -1;
}
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
step);
if (step == 1)
return list_ass_slice(self, start, stop, value);
/* Make sure s[5:2] = [..] inserts at the right place:
before 5, not before 2. */
if ((step < 0 && start < stop) ||
(step > 0 && start > stop))
stop = start;
if (value == NULL) {
/* delete slice */
@ -3618,6 +3624,12 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
Py_ssize_t i;
int res;
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
step);
if (step == 1)
return list_ass_slice(self, start, stop, value);
if (slicelength <= 0)
return 0;
@ -3695,6 +3707,15 @@ list_ass_subscript(PyObject* _self, PyObject* item, PyObject* value)
if (!seq)
return -1;
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
step);
if (step == 1) {
int res = list_ass_slice(self, start, stop, seq);
Py_DECREF(seq);
return res;
}
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
PyErr_Format(PyExc_ValueError,
"attempt to assign sequence of "