Skip to content

Commit 296d45e

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

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
@@ -162,5 +162,31 @@ class L(list): pass
162162
with self.assertRaises(TypeError):
163163
(3,) + L([1,2])
164164

165+
def test_count_index_remove_crashes(self):
166+
# bpo-38610: The count(), index(), and remove() methods were not
167+
# holding strong references to list elements while calling
168+
# PyObject_RichCompareBool().
169+
class X:
170+
def __eq__(self, other):
171+
lst.clear()
172+
return NotImplemented
173+
174+
lst = [X()]
175+
with self.assertRaises(ValueError):
176+
lst.index(lst)
177+
178+
class L(list):
179+
def __eq__(self, other):
180+
str(other)
181+
return NotImplemented
182+
183+
lst = L([X()])
184+
lst.count(lst)
185+
186+
lst = L([X()])
187+
with self.assertRaises(ValueError):
188+
lst.remove(lst)
189+
190+
165191
if __name__ == "__main__":
166192
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
@@ -2506,7 +2506,10 @@ list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
25062506
stop = 0;
25072507
}
25082508
for (i = start; i < stop && i < Py_SIZE(self); i++) {
2509-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2509+
PyObject *obj = self->ob_item[i];
2510+
Py_INCREF(obj);
2511+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2512+
Py_DECREF(obj);
25102513
if (cmp > 0)
25112514
return PyLong_FromSsize_t(i);
25122515
else if (cmp < 0)
@@ -2533,7 +2536,10 @@ list_count(PyListObject *self, PyObject *value)
25332536
Py_ssize_t i;
25342537

25352538
for (i = 0; i < Py_SIZE(self); i++) {
2536-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2539+
PyObject *obj = self->ob_item[i];
2540+
Py_INCREF(obj);
2541+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2542+
Py_DECREF(obj);
25372543
if (cmp > 0)
25382544
count++;
25392545
else if (cmp < 0)
@@ -2560,7 +2566,10 @@ list_remove(PyListObject *self, PyObject *value)
25602566
Py_ssize_t i;
25612567

25622568
for (i = 0; i < Py_SIZE(self); i++) {
2563-
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
2569+
PyObject *obj = self->ob_item[i];
2570+
Py_INCREF(obj);
2571+
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
2572+
Py_DECREF(obj);
25642573
if (cmp > 0) {
25652574
if (list_ass_slice(self, i, i+1,
25662575
(PyObject *)NULL) == 0)

0 commit comments

Comments
 (0)