mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
[3.11] gh-120384: gh-120298: Fix array-out-of-bounds & use after free list (GH-121345)
(cherry picked from commit 8334a1b55c)
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
88f3f5b5f1
commit
0cd888b8d3
5 changed files with 79 additions and 13 deletions
|
|
@ -192,6 +192,14 @@ def test_setslice(self):
|
|||
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -229,6 +229,31 @@ def __eq__(self, other):
|
|||
list4 = [1]
|
||||
self.assertFalse(list3 == list4)
|
||||
|
||||
def test_lt_operator_modifying_operand(self):
|
||||
# See gh-120298
|
||||
class evil:
|
||||
def __lt__(self, other):
|
||||
other.clear()
|
||||
return NotImplemented
|
||||
|
||||
a = [[evil()]]
|
||||
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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Fix use-after free in ``list_richcompare_impl`` which can be invoked via
|
||||
some specificly tailored evil input.
|
||||
|
|
@ -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.
|
||||
|
|
@ -2757,7 +2757,14 @@ list_richcompare(PyObject *v, PyObject *w, int op)
|
|||
}
|
||||
|
||||
/* Compare the final item again using the proper operator */
|
||||
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
|
||||
PyObject *vitem = vl->ob_item[i];
|
||||
PyObject *witem = wl->ob_item[i];
|
||||
Py_INCREF(vitem);
|
||||
Py_INCREF(witem);
|
||||
PyObject *result = PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
|
||||
Py_DECREF(vitem);
|
||||
Py_DECREF(witem);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
|
@ -2927,6 +2934,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)
|
||||
{
|
||||
|
|
@ -2939,22 +2963,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 */
|
||||
|
|
@ -2963,6 +2976,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;
|
||||
|
||||
|
|
@ -3038,6 +3057,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 "
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue