Skip to content

Commit 15f0a45

Browse files
bpo-33930: Fix segfault with deep recursion when cleaning method objects (GH-27678) (GH-27720)
(cherry picked from commit bfc2d5a) Co-authored-by: Pablo Galindo Salgado <[email protected]>
1 parent d27e2f4 commit 15f0a45

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

Lib/test/test_exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,21 @@ def g():
11391139
self.assertIsInstance(v, RecursionError, type(v))
11401140
self.assertIn("maximum recursion depth exceeded", str(v))
11411141

1142+
1143+
@cpython_only
1144+
def test_crashcan_recursion(self):
1145+
# See bpo-33930
1146+
1147+
def foo():
1148+
o = object()
1149+
for x in range(1_000_000):
1150+
# Create a big chain of method objects that will trigger
1151+
# a deep chain of calls when they need to be destructed.
1152+
o = o.__dir__
1153+
1154+
foo()
1155+
support.gc_collect()
1156+
11421157
@cpython_only
11431158
def test_recursion_normalizing_exception(self):
11441159
# Issue #22898.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix segmentation fault with deep recursion when cleaning method objects.
2+
Patch by Augusto Goulart and Pablo Galindo.

Objects/methodobject.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ PyCMethod_GetClass(PyObject *op)
160160
static void
161161
meth_dealloc(PyCFunctionObject *m)
162162
{
163-
_PyObject_GC_UNTRACK(m);
163+
// The Py_TRASHCAN mechanism requires that we be able to
164+
// call PyObject_GC_UnTrack twice on an object.
165+
PyObject_GC_UnTrack(m);
166+
Py_TRASHCAN_BEGIN(m, meth_dealloc);
164167
if (m->m_weakreflist != NULL) {
165168
PyObject_ClearWeakRefs((PyObject*) m);
166169
}
@@ -170,6 +173,7 @@ meth_dealloc(PyCFunctionObject *m)
170173
Py_XDECREF(m->m_self);
171174
Py_XDECREF(m->m_module);
172175
PyObject_GC_Del(m);
176+
Py_TRASHCAN_END;
173177
}
174178

175179
static PyObject *

0 commit comments

Comments
 (0)