]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-132713: Fix repr(list) race condition (#132801) (#132809)
authorVictor Stinner <vstinner@python.org>
Wed, 23 Apr 2025 13:44:33 +0000 (15:44 +0200)
committerGitHub <noreply@github.com>
Wed, 23 Apr 2025 13:44:33 +0000 (15:44 +0200)
Hold a strong reference to the item while calling repr(item).

(cherry picked from commit a4ea80d52394bafffb2257abbe815c7ffdb003a3)

Lib/test/test_list.py
Misc/NEWS.d/next/Core and Builtins/2025-04-22-16-38-43.gh-issue-132713.mBWTSZ.rst [new file with mode: 0644]
Objects/listobject.c

index 005374f429399f380ac31eabc30b61d37eb8edf7..23ef902aa0be34f6f15e41badfd5ebdeb22fe5d0 100644 (file)
@@ -116,6 +116,19 @@ class ListTest(list_tests.CommonTest):
         with self.assertRaises((MemoryError, OverflowError)):
             lst *= size
 
+    def test_repr_mutate(self):
+        class Obj:
+            @staticmethod
+            def __repr__():
+                try:
+                    mylist.pop()
+                except IndexError:
+                    pass
+                return 'obj'
+
+        mylist = [Obj() for _ in range(5)]
+        self.assertEqual(repr(mylist), '[obj, obj, obj]')
+
     def test_repr_large(self):
         # Check the repr of large list objects
         def check(n):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-04-22-16-38-43.gh-issue-132713.mBWTSZ.rst b/Misc/NEWS.d/next/Core and Builtins/2025-04-22-16-38-43.gh-issue-132713.mBWTSZ.rst
new file mode 100644 (file)
index 0000000..877b423
--- /dev/null
@@ -0,0 +1,2 @@
+Fix ``repr(list)`` race condition: hold a strong reference to the item while
+calling ``repr(item)``. Patch by Victor Stinner.
index 65a8b06d978df44d4adb55e4a78891ca054b21ef..04a31f1f34a4bba68a0173b4225e232544314980 100644 (file)
@@ -585,6 +585,7 @@ list_repr_impl(PyListObject *v)
 {
     PyObject *s;
     _PyUnicodeWriter writer;
+    PyObject *item = NULL;
     Py_ssize_t i = Py_ReprEnter((PyObject*)v);
     if (i != 0) {
         return i > 0 ? PyUnicode_FromString("[...]") : NULL;
@@ -601,12 +602,15 @@ list_repr_impl(PyListObject *v)
     /* Do repr() on each element.  Note that this may mutate the list,
        so must refetch the list size on each iteration. */
     for (i = 0; i < Py_SIZE(v); ++i) {
+        /* Hold a strong reference since repr(item) can mutate the list */
+        item = Py_NewRef(v->ob_item[i]);
+
         if (i > 0) {
             if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
                 goto error;
         }
 
-        s = PyObject_Repr(v->ob_item[i]);
+        s = PyObject_Repr(item);
         if (s == NULL)
             goto error;
 
@@ -615,6 +619,7 @@ list_repr_impl(PyListObject *v)
             goto error;
         }
         Py_DECREF(s);
+        Py_CLEAR(item);
     }
 
     writer.overallocate = 0;
@@ -625,6 +630,7 @@ list_repr_impl(PyListObject *v)
     return _PyUnicodeWriter_Finish(&writer);
 
 error:
+    Py_XDECREF(item);
     _PyUnicodeWriter_Dealloc(&writer);
     Py_ReprLeave((PyObject *)v);
     return NULL;