Skip to content

Commit bfc2d5a

Browse files
authored
bpo-33930: Fix segfault with deep recursion when cleaning method objects (GH-27678)
1 parent c0ab59f commit bfc2d5a

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

Lib/test/test_exceptions.py

+15
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,21 @@ def g():
11691169
self.assertIsInstance(v, RecursionError, type(v))
11701170
self.assertIn("maximum recursion depth exceeded", str(v))
11711171

1172+
1173+
@cpython_only
1174+
def test_crashcan_recursion(self):
1175+
# See bpo-33930
1176+
1177+
def foo():
1178+
o = object()
1179+
for x in range(1_000_000):
1180+
# Create a big chain of method objects that will trigger
1181+
# a deep chain of calls when they need to be destructed.
1182+
o = o.__dir__
1183+
1184+
foo()
1185+
support.gc_collect()
1186+
11721187
@cpython_only
11731188
def test_recursion_normalizing_exception(self):
11741189
# Issue #22898.
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

+5-1
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)