Skip to content

Commit d75eddc

Browse files
[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 8334a1b) Co-authored-by: Nikita Sobolev <[email protected]>
1 parent e58bece commit d75eddc

File tree

4 files changed

+58
-12
lines changed

4 files changed

+58
-12
lines changed

Lib/test/list_tests.py

Lines changed: 8 additions & 0 deletions
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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,20 @@ def __lt__(self, other):
240240
with self.assertRaises(TypeError):
241241
a[0] < a
242242

243+
def test_list_index_modifing_operand(self):
244+
# See gh-120384
245+
class evil:
246+
def __init__(self, lst):
247+
self.lst = lst
248+
def __iter__(self):
249+
yield from self.lst
250+
self.lst.clear()
251+
252+
lst = list(range(5))
253+
operand = evil(lst)
254+
with self.assertRaises(ValueError):
255+
lst[::-1] = operand
256+
243257
@cpython_only
244258
def test_preallocation(self):
245259
iterable = [0] * 10
Lines changed: 3 additions & 0 deletions
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

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,6 +2935,23 @@ list_subscript(PyListObject* self, PyObject* item)
29352935
}
29362936
}
29372937

2938+
static Py_ssize_t
2939+
adjust_slice_indexes(PyListObject *lst,
2940+
Py_ssize_t *start, Py_ssize_t *stop,
2941+
Py_ssize_t step)
2942+
{
2943+
Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop,
2944+
step);
2945+
2946+
/* Make sure s[5:2] = [..] inserts at the right place:
2947+
before 5, not before 2. */
2948+
if ((step < 0 && *start < *stop) ||
2949+
(step > 0 && *start > *stop))
2950+
*stop = *start;
2951+
2952+
return slicelength;
2953+
}
2954+
29382955
static int
29392956
list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
29402957
{
@@ -2947,22 +2964,11 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
29472964
return list_ass_item(self, i, value);
29482965
}
29492966
else if (PySlice_Check(item)) {
2950-
Py_ssize_t start, stop, step, slicelength;
2967+
Py_ssize_t start, stop, step;
29512968

29522969
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
29532970
return -1;
29542971
}
2955-
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
2956-
step);
2957-
2958-
if (step == 1)
2959-
return list_ass_slice(self, start, stop, value);
2960-
2961-
/* Make sure s[5:2] = [..] inserts at the right place:
2962-
before 5, not before 2. */
2963-
if ((step < 0 && start < stop) ||
2964-
(step > 0 && start > stop))
2965-
stop = start;
29662972

29672973
if (value == NULL) {
29682974
/* delete slice */
@@ -2971,6 +2977,12 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
29712977
Py_ssize_t i;
29722978
int res;
29732979

2980+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
2981+
step);
2982+
2983+
if (step == 1)
2984+
return list_ass_slice(self, start, stop, value);
2985+
29742986
if (slicelength <= 0)
29752987
return 0;
29762988

@@ -3046,6 +3058,15 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
30463058
if (!seq)
30473059
return -1;
30483060

3061+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
3062+
step);
3063+
3064+
if (step == 1) {
3065+
int res = list_ass_slice(self, start, stop, seq);
3066+
Py_DECREF(seq);
3067+
return res;
3068+
}
3069+
30493070
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
30503071
PyErr_Format(PyExc_ValueError,
30513072
"attempt to assign sequence of "

0 commit comments

Comments
 (0)