Skip to content

Commit 3de0f55

Browse files
authored
[3.13] gh-132713: Fix repr(list) race condition (#132801) (#132809)
Hold a strong reference to the item while calling repr(item). (cherry picked from commit a4ea80d)
1 parent 3a130c1 commit 3de0f55

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

Lib/test/test_list.py

+13
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@ def test_list_resize_overflow(self):
116116
with self.assertRaises((MemoryError, OverflowError)):
117117
lst *= size
118118

119+
def test_repr_mutate(self):
120+
class Obj:
121+
@staticmethod
122+
def __repr__():
123+
try:
124+
mylist.pop()
125+
except IndexError:
126+
pass
127+
return 'obj'
128+
129+
mylist = [Obj() for _ in range(5)]
130+
self.assertEqual(repr(mylist), '[obj, obj, obj]')
131+
119132
def test_repr_large(self):
120133
# Check the repr of large list objects
121134
def check(n):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``repr(list)`` race condition: hold a strong reference to the item while
2+
calling ``repr(item)``. Patch by Victor Stinner.

Objects/listobject.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ list_repr_impl(PyListObject *v)
585585
{
586586
PyObject *s;
587587
_PyUnicodeWriter writer;
588+
PyObject *item = NULL;
588589
Py_ssize_t i = Py_ReprEnter((PyObject*)v);
589590
if (i != 0) {
590591
return i > 0 ? PyUnicode_FromString("[...]") : NULL;
@@ -601,12 +602,15 @@ list_repr_impl(PyListObject *v)
601602
/* Do repr() on each element. Note that this may mutate the list,
602603
so must refetch the list size on each iteration. */
603604
for (i = 0; i < Py_SIZE(v); ++i) {
605+
/* Hold a strong reference since repr(item) can mutate the list */
606+
item = Py_NewRef(v->ob_item[i]);
607+
604608
if (i > 0) {
605609
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
606610
goto error;
607611
}
608612

609-
s = PyObject_Repr(v->ob_item[i]);
613+
s = PyObject_Repr(item);
610614
if (s == NULL)
611615
goto error;
612616

@@ -615,6 +619,7 @@ list_repr_impl(PyListObject *v)
615619
goto error;
616620
}
617621
Py_DECREF(s);
622+
Py_CLEAR(item);
618623
}
619624

620625
writer.overallocate = 0;
@@ -625,6 +630,7 @@ list_repr_impl(PyListObject *v)
625630
return _PyUnicodeWriter_Finish(&writer);
626631

627632
error:
633+
Py_XDECREF(item);
628634
_PyUnicodeWriter_Dealloc(&writer);
629635
Py_ReprLeave((PyObject *)v);
630636
return NULL;

0 commit comments

Comments
 (0)