Skip to content

Commit cf7cdaa

Browse files
ZackerySpytzcorona10
authored andcommitted
bpo-38610: Fix possible crashes in several list methods (pythonGH-17022)
Hold strong references to list elements while calling PyObject_RichCompareBool().
1 parent c563f40 commit cf7cdaa

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
@@ -151,5 +151,31 @@ class L(list): pass
151151
with self.assertRaises(TypeError):
152152
(3,) + L([1,2])
153153

154+
def test_count_index_remove_crashes(self):
155+
# bpo-38610: The count(), index(), and remove() methods were not
156+
# holding strong references to list elements while calling
157+
# PyObject_RichCompareBool().
158+
class X:
159+
def __eq__(self, other):
160+
lst.clear()
161+
return NotImplemented
162+
163+
lst = [X()]
164+
with self.assertRaises(ValueError):
165+
lst.index(lst)
166+
167+
class L(list):
168+
def __eq__(self, other):
169+
str(other)
170+
return NotImplemented
171+
172+
lst = L([X()])
173+
lst.count(lst)
174+
175+
lst = L([X()])
176+
with self.assertRaises(ValueError):
177+
lst.remove(lst)
178+
179+
154180
if __name__ == "__main__":
155181
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
@@ -2164,7 +2164,10 @@ listindex(PyListObject *self, PyObject *args)
21642164
stop = 0;
21652165
}
21662166
for (i = start; i < stop && i < Py_SIZE(self); i++) {
2167-
int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
2167+
PyObject *obj = self->ob_item[i];
2168+
Py_INCREF(obj);
2169+
int cmp = PyObject_RichCompareBool(obj, v, Py_EQ);
2170+
Py_DECREF(obj);
21682171
if (cmp > 0)
21692172
return PyLong_FromSsize_t(i);
21702173
else if (cmp < 0)
@@ -2181,7 +2184,10 @@ listcount(PyListObject *self, PyObject *v)
21812184
Py_ssize_t i;
21822185

21832186
for (i = 0; i < Py_SIZE(self); i++) {
2184-
int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
2187+
PyObject *obj = self->ob_item[i];
2188+
Py_INCREF(obj);
2189+
int cmp = PyObject_RichCompareBool(obj, v, Py_EQ);
2190+
Py_DECREF(obj);
21852191
if (cmp > 0)
21862192
count++;
21872193
else if (cmp < 0)
@@ -2196,7 +2202,10 @@ listremove(PyListObject *self, PyObject *v)
21962202
Py_ssize_t i;
21972203

21982204
for (i = 0; i < Py_SIZE(self); i++) {
2199-
int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
2205+
PyObject *obj = self->ob_item[i];
2206+
Py_INCREF(obj);
2207+
int cmp = PyObject_RichCompareBool(obj, v, Py_EQ);
2208+
Py_DECREF(obj);
22002209
if (cmp > 0) {
22012210
if (list_ass_slice(self, i, i+1,
22022211
(PyObject *)NULL) == 0)

0 commit comments

Comments
 (0)