summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-06-21 11:16:24 (GMT)
committerGitHub <noreply@github.com>2024-06-21 11:16:24 (GMT)
commitf3d7823ede41f7650ae7a199186cb63f62031441 (patch)
tree53abaac8159c7d00ab1c1849590e6edcc7af9dd5
parent730285519ec6afb571409ec7fd3dbdf131bfbdab (diff)
downloadcpython-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.py8
-rw-r--r--Lib/test/test_list.py14
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-06-13-12-17-52.gh-issue-120384.w1UBGl.rst3
-rw-r--r--Objects/listobject.c45
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 "