From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:08:22 +0000 (+0200) Subject: [3.12] gh-120384: Fix array-out-of-bounds crash in `list_ass_subscript` (GH-120442... X-Git-Tag: v3.12.5~191 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d75eddcf36986ae971f42fd516f737169081e182;p=thirdparty%2FPython%2Fcpython.git [3.12] gh-120384: Fix array-out-of-bounds crash in `list_ass_subscript` (GH-120442) (#120825) gh-120384: Fix array-out-of-bounds crash in `list_ass_subscript` (GH-120442) (cherry picked from commit 8334a1b55c93068f5d243852029baa83377ff6c9) Co-authored-by: Nikita Sobolev --- diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index b1ef332522d2..ac13b110b208 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -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] diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 4207f2b36454..77264ed7e80a 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -240,6 +240,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 diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst new file mode 100644 index 000000000000..4a4db821ce29 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst @@ -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. diff --git a/Objects/listobject.c b/Objects/listobject.c index ee724dbe1460..d017f34b94f0 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2935,6 +2935,23 @@ list_subscript(PyListObject* 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(PyListObject* self, PyObject* item, PyObject* value) { @@ -2947,22 +2964,11 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) return list_ass_item(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 */ @@ -2971,6 +2977,12 @@ list_ass_subscript(PyListObject* 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; @@ -3046,6 +3058,15 @@ list_ass_subscript(PyListObject* 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 "