From 15f0a45b2822607f2c38685a72d06f050e24b215 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Aug 2021 01:32:24 -0700 Subject: bpo-33930: Fix segfault with deep recursion when cleaning method objects (GH-27678) (GH-27720) (cherry picked from commit bfc2d5a5c4550ab3a2fadeb9459b4bd948ff61a2) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_exceptions.py | 15 +++++++++++++++ .../2021-08-09-14-29-52.bpo-33930.--5LQ-.rst | 2 ++ Objects/methodobject.c | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-08-09-14-29-52.bpo-33930.--5LQ-.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index cd7050b..abb9000 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1139,6 +1139,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 index 0000000..827dd3f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-09-14-29-52.bpo-33930.--5LQ-.rst @@ -0,0 +1,2 @@ +Fix segmentation fault with deep recursion when cleaning method objects. +Patch by Augusto Goulart and Pablo Galindo. diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 7b43041..2df63cf 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -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 * -- cgit v0.12