diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-06-21 11:16:24 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-21 11:16:24 (GMT) |
commit | f3d7823ede41f7650ae7a199186cb63f62031441 (patch) | |
tree | 53abaac8159c7d00ab1c1849590e6edcc7af9dd5 | |
parent | 730285519ec6afb571409ec7fd3dbdf131bfbdab (diff) | |
download | cpython-f3d7823ede41f7650ae7a199186cb63f62031441.zip cpython-f3d7823ede41f7650ae7a199186cb63f62031441.tar.gz cpython-f3d7823ede41f7650ae7a199186cb63f62031441.tar.bz2 |
[3.13] gh-120384: Fix array-out-of-bounds crash in `list_ass_subscript` (GH-120442) (#120826)
gh-120384: Fix array-out-of-bounds crash in `list_ass_subscript` (GH-120442)
(cherry picked from commit 8334a1b55c93068f5d243852029baa83377ff6c9)
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
-rw-r--r-- | Lib/test/list_tests.py | 8 | ||||
-rw-r--r-- | Lib/test/test_list.py | 14 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst | 3 | ||||
-rw-r--r-- | Objects/listobject.c | 45 |
4 files changed, 58 insertions, 12 deletions
diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index 89cd10f..dbc5ef4 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 d21429f..4d2d547 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -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 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 0000000..4a4db82 --- /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 6829d5d..a05ddea 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -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 " |