Skip to content

Commit a4ea80d

Browse files
authored
gh-132713: Fix repr(list) race condition (#132801)
Hold a strong reference to the item while calling repr(item).
1 parent 722c501 commit a4ea80d

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

Lib/test/test_list.py

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

121+
def test_repr_mutate(self):
122+
class Obj:
123+
@staticmethod
124+
def __repr__():
125+
try:
126+
mylist.pop()
127+
except IndexError:
128+
pass
129+
return 'obj'
130+
131+
mylist = [Obj() for _ in range(5)]
132+
self.assertEqual(repr(mylist), '[obj, obj, obj]')
133+
121134
def test_repr_large(self):
122135
# Check the repr of large list objects
123136
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

+11-1
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ list_repr_impl(PyListObject *v)
583583
/* "[" + "1" + ", 2" * (len - 1) + "]" */
584584
Py_ssize_t prealloc = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1;
585585
PyUnicodeWriter *writer = PyUnicodeWriter_Create(prealloc);
586+
PyObject *item = NULL;
586587
if (writer == NULL) {
587588
goto error;
588589
}
@@ -594,6 +595,13 @@ list_repr_impl(PyListObject *v)
594595
/* Do repr() on each element. Note that this may mutate the list,
595596
so must refetch the list size on each iteration. */
596597
for (Py_ssize_t i = 0; i < Py_SIZE(v); ++i) {
598+
item = list_get_item_ref(v, i);
599+
if (item == NULL) {
600+
// List truncated while iterating on it
601+
PyErr_Clear();
602+
break;
603+
}
604+
597605
if (i > 0) {
598606
if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
599607
goto error;
@@ -603,9 +611,10 @@ list_repr_impl(PyListObject *v)
603611
}
604612
}
605613

606-
if (PyUnicodeWriter_WriteRepr(writer, v->ob_item[i]) < 0) {
614+
if (PyUnicodeWriter_WriteRepr(writer, item) < 0) {
607615
goto error;
608616
}
617+
Py_CLEAR(item);
609618
}
610619

611620
if (PyUnicodeWriter_WriteChar(writer, ']') < 0) {
@@ -616,6 +625,7 @@ list_repr_impl(PyListObject *v)
616625
return PyUnicodeWriter_Finish(writer);
617626

618627
error:
628+
Py_XDECREF(item);
619629
PyUnicodeWriter_Discard(writer);
620630
Py_ReprLeave((PyObject *)v);
621631
return NULL;

0 commit comments

Comments
 (0)