Skip to content

Commit fcaf14c

Browse files
bpo-38610: Fix possible crashes in several list methods (GH-17022)
Hold strong references to list elements while calling PyObject_RichCompareBool(). (cherry picked from commit d9e561d) Co-authored-by: Zackery Spytz <[email protected]>
1 parent cbfafa3 commit fcaf14c

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

Lib/test/test_list.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,5 +166,31 @@ def test_preallocation(self):
166166
self.assertEqual(iter_size, sys.getsizeof(list([0] * 10)))
167167
self.assertEqual(iter_size, sys.getsizeof(list(range(10))))
168168

169+
def test_count_index_remove_crashes(self):
170+
# bpo-38610: The count(), index(), and remove() methods were not
171+
# holding strong references to list elements while calling
172+
# PyObject_RichCompareBool().
173+
class X:
174+
def __eq__(self, other):
175+
lst.clear()
176+
return NotImplemented
177+
178+
lst = [X()]
179+
with self.assertRaises(ValueError):
180+
lst.index(lst)
181+
182+
class L(list):
183+
def __eq__(self, other):
184+
str(other)
185+
return NotImplemented
186+
187+
lst = L([X()])
188+
lst.count(lst)
189+
190+
lst = L([X()])
191+
with self.assertRaises(ValueError):
192+
lst.remove(lst)
193+
194+
169195
if __name__ == "__main__":
170196
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix possible crashes in several list methods by holding strong references to
2+
list elements when calling :c:func:`PyObject_RichCompareBool`.

Objects/listobject.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,7 +2555,10 @@ list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
25552555
stop = 0;
25562556
}
25572557
for (i = start; i < stop && i < Py_SIZE(self); i++) {
2558-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2558+
PyObject *obj = self->ob_item[i];
2559+
Py_INCREF(obj);
2560+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2561+
Py_DECREF(obj);
25592562
if (cmp > 0)
25602563
return PyLong_FromSsize_t(i);
25612564
else if (cmp < 0)
@@ -2582,7 +2585,10 @@ list_count(PyListObject *self, PyObject *value)
25822585
Py_ssize_t i;
25832586

25842587
for (i = 0; i < Py_SIZE(self); i++) {
2585-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2588+
PyObject *obj = self->ob_item[i];
2589+
Py_INCREF(obj);
2590+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2591+
Py_DECREF(obj);
25862592
if (cmp > 0)
25872593
count++;
25882594
else if (cmp < 0)
@@ -2609,7 +2615,10 @@ list_remove(PyListObject *self, PyObject *value)
26092615
Py_ssize_t i;
26102616

26112617
for (i = 0; i < Py_SIZE(self); i++) {
2612-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2618+
PyObject *obj = self->ob_item[i];
2619+
Py_INCREF(obj);
2620+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2621+
Py_DECREF(obj);
26132622
if (cmp > 0) {
26142623
if (list_ass_slice(self, i, i+1,
26152624
(PyObject *)NULL) == 0)

0 commit comments

Comments
 (0)