Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a4ea80d

Browse filesBrowse 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
Copy full SHA for a4ea80d

File tree

Expand file treeCollapse file tree

3 files changed

+26
-1
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+26
-1
lines changed

‎Lib/test/test_list.py

Copy file name to clipboardExpand all lines: Lib/test/test_list.py
+13Lines changed: 13 additions & 0 deletions
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):
+2Lines changed: 2 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: Objects/listobject.c
+11-1Lines changed: 11 additions & 1 deletion
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.