]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-33930: Fix segfault with deep recursion when cleaning method objects (GH-27678)
authorPablo Galindo Salgado <Pablogsal@gmail.com>
Tue, 10 Aug 2021 23:34:14 +0000 (00:34 +0100)
committerGitHub <noreply@github.com>
Tue, 10 Aug 2021 23:34:14 +0000 (00:34 +0100)
Lib/test/test_exceptions.py
Misc/NEWS.d/next/Core and Builtins/2021-08-09-14-29-52.bpo-33930.--5LQ-.rst [new file with mode: 0644]
Objects/methodobject.c

index 593107f290dc59caeccab7cb11b9bef90dbb3552..8bcb4b0f789a8a919c0b6ef4ca542cc20579e755 100644 (file)
@@ -1169,6 +1169,21 @@ class ExceptionTests(unittest.TestCase):
         self.assertIsInstance(v, RecursionError, type(v))
         self.assertIn("maximum recursion depth exceeded", str(v))
 
+
+    @cpython_only
+    def test_crashcan_recursion(self):
+        # See bpo-33930
+
+        def foo():
+            o = object()
+            for x in range(1_000_000):
+                # Create a big chain of method objects that will trigger
+                # a deep chain of calls when they need to be destructed.
+                o = o.__dir__
+
+        foo()
+        support.gc_collect()
+
     @cpython_only
     def test_recursion_normalizing_exception(self):
         # Issue #22898.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-09-14-29-52.bpo-33930.--5LQ-.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-09-14-29-52.bpo-33930.--5LQ-.rst
new file mode 100644 (file)
index 0000000..827dd3f
--- /dev/null
@@ -0,0 +1,2 @@
+Fix segmentation fault with deep recursion when cleaning method objects.
+Patch by Augusto Goulart and Pablo Galindo.
index 7b430416c5a048715c1e8e91b4128c46ca25f828..2df63cfdf6a818e2473b6217017616007dca166d 100644 (file)
@@ -160,7 +160,10 @@ PyCMethod_GetClass(PyObject *op)
 static void
 meth_dealloc(PyCFunctionObject *m)
 {
-    _PyObject_GC_UNTRACK(m);
+    // The Py_TRASHCAN mechanism requires that we be able to
+    // call PyObject_GC_UnTrack twice on an object.
+    PyObject_GC_UnTrack(m);
+    Py_TRASHCAN_BEGIN(m, meth_dealloc);
     if (m->m_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject*) m);
     }
@@ -170,6 +173,7 @@ meth_dealloc(PyCFunctionObject *m)
     Py_XDECREF(m->m_self);
     Py_XDECREF(m->m_module);
     PyObject_GC_Del(m);
+    Py_TRASHCAN_END;
 }
 
 static PyObject *