Skip to content

Commit 42762bb

Browse files
miss-islingtongpsheadsobolevnambv
authored
[3.9] pythongh-120384: pythongh-120298: Fix array-out-of-bounds & use after free list (pythonGH-121345) (pythonGH-140834)
(cherry picked from commit 8334a1b) (cherry picked from commit 0cd888b) Co-authored-by: Gregory P. Smith <[email protected]> Co-authored-by: Nikita Sobolev <[email protected]> Co-authored-by: Łukasz Langa <[email protected]>
1 parent 90719e3 commit 42762bb

File tree

5 files changed

+79
-13
lines changed

5 files changed

+79
-13
lines changed

Lib/test/list_tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ def test_setslice(self):
206206

207207
self.assertRaises(TypeError, a.__setitem__)
208208

209+
def test_slice_assign_iterator(self):
210+
x = self.type2test(range(5))
211+
x[0:3] = reversed(range(3))
212+
self.assertEqual(x, self.type2test([2, 1, 0, 3, 4]))
213+
214+
x[:] = reversed(range(3))
215+
self.assertEqual(x, self.type2test([2, 1, 0]))
216+
209217
def test_delslice(self):
210218
a = self.type2test([0, 1])
211219
del a[1:2]

Lib/test/test_list.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,31 @@ def __eq__(self, other):
201201
list4 = [1]
202202
self.assertFalse(list3 == list4)
203203

204+
def test_lt_operator_modifying_operand(self):
205+
# See gh-120298
206+
class evil:
207+
def __lt__(self, other):
208+
other.clear()
209+
return NotImplemented
210+
211+
a = [[evil()]]
212+
with self.assertRaises(TypeError):
213+
a[0] < a
214+
215+
def test_list_index_modifing_operand(self):
216+
# See gh-120384
217+
class evil:
218+
def __init__(self, lst):
219+
self.lst = lst
220+
def __iter__(self):
221+
yield from self.lst
222+
self.lst.clear()
223+
224+
lst = list(range(5))
225+
operand = evil(lst)
226+
with self.assertRaises(ValueError):
227+
lst[::-1] = operand
228+
204229
@cpython_only
205230
def test_preallocation(self):
206231
iterable = [0] * 10
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix use-after free in ``list_richcompare_impl`` which can be invoked via
2+
some specificly tailored evil input.
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: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,7 +2679,14 @@ list_richcompare(PyObject *v, PyObject *w, int op)
26792679
}
26802680

26812681
/* Compare the final item again using the proper operator */
2682-
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
2682+
PyObject *vitem = vl->ob_item[i];
2683+
PyObject *witem = wl->ob_item[i];
2684+
Py_INCREF(vitem);
2685+
Py_INCREF(witem);
2686+
PyObject *result = PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
2687+
Py_DECREF(vitem);
2688+
Py_DECREF(witem);
2689+
return result;
26832690
}
26842691

26852692
/*[clinic input]
@@ -2863,6 +2870,23 @@ list_subscript(PyListObject* self, PyObject* item)
28632870
}
28642871
}
28652872

2873+
static Py_ssize_t
2874+
adjust_slice_indexes(PyListObject *lst,
2875+
Py_ssize_t *start, Py_ssize_t *stop,
2876+
Py_ssize_t step)
2877+
{
2878+
Py_ssize_t slicelength = PySlice_AdjustIndices(Py_SIZE(lst), start, stop,
2879+
step);
2880+
2881+
/* Make sure s[5:2] = [..] inserts at the right place:
2882+
before 5, not before 2. */
2883+
if ((step < 0 && *start < *stop) ||
2884+
(step > 0 && *start > *stop))
2885+
*stop = *start;
2886+
2887+
return slicelength;
2888+
}
2889+
28662890
static int
28672891
list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
28682892
{
@@ -2875,22 +2899,11 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
28752899
return list_ass_item(self, i, value);
28762900
}
28772901
else if (PySlice_Check(item)) {
2878-
Py_ssize_t start, stop, step, slicelength;
2902+
Py_ssize_t start, stop, step;
28792903

28802904
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
28812905
return -1;
28822906
}
2883-
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
2884-
step);
2885-
2886-
if (step == 1)
2887-
return list_ass_slice(self, start, stop, value);
2888-
2889-
/* Make sure s[5:2] = [..] inserts at the right place:
2890-
before 5, not before 2. */
2891-
if ((step < 0 && start < stop) ||
2892-
(step > 0 && start > stop))
2893-
stop = start;
28942907

28952908
if (value == NULL) {
28962909
/* delete slice */
@@ -2899,6 +2912,12 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
28992912
Py_ssize_t i;
29002913
int res;
29012914

2915+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
2916+
step);
2917+
2918+
if (step == 1)
2919+
return list_ass_slice(self, start, stop, value);
2920+
29022921
if (slicelength <= 0)
29032922
return 0;
29042923

@@ -2974,6 +2993,15 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
29742993
if (!seq)
29752994
return -1;
29762995

2996+
Py_ssize_t slicelength = adjust_slice_indexes(self, &start, &stop,
2997+
step);
2998+
2999+
if (step == 1) {
3000+
int res = list_ass_slice(self, start, stop, seq);
3001+
Py_DECREF(seq);
3002+
return res;
3003+
}
3004+
29773005
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
29783006
PyErr_Format(PyExc_ValueError,
29793007
"attempt to assign sequence of "

0 commit comments

Comments
 (0)