Skip to content

gh-137894: Fix segmentation fault in deeply nested filter() iterator chains #137896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
15 changes: 14 additions & 1 deletion Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,6 @@ def test_filter_pickle(self):

@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
@support.requires_resource('cpu')
def test_filter_dealloc(self):
# Tests recursive deallocation of nested filter objects using the
# thrashcan mechanism. See gh-102356 for more details.
Expand All @@ -1131,6 +1130,20 @@ def test_filter_dealloc(self):
i = filter(bool, i)
del i
gc.collect()
6
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
@support.requires_resource('cpu')
Copy link
Member

@picnixz picnixz Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really need a CPU resource? (or maybe it's because of i = filter(bool, i)? how long does the test take? (seconds or minutes?)

def test_filter_deep_nesting_recursion_error(self):
# gh-137894: Test that deeply nested filter() iterator chains
# raise RecursionError instead of causing segmentation fault.
# This verifies that the tp_clear method prevents stack overflow
# during garbage collection of cyclic references.
i = filter(bool, range(1000000))
for _ in range(100000):
i = filter(bool, i)

self.assertRaises(RecursionError, list, i)

def test_getattr(self):
self.assertTrue(getattr(sys, 'stdout') is sys.stdout)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix segmentation fault in deeply nested :func:`filter` iterator chains.
Deeply nested filter iterators now properly raise :exc:`RecursionError`
instead of crashing the interpreter.
11 changes: 10 additions & 1 deletion Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,15 @@ filter_traverse(PyObject *self, visitproc visit, void *arg)
return 0;
}

static int
filter_clear(PyObject *self)
{
filterobject *lz = _filterobject_CAST(self);
Py_CLEAR(lz->it);
Py_CLEAR(lz->func);
return 0;
}

static PyObject *
filter_next(PyObject *self)
{
Expand Down Expand Up @@ -661,7 +670,7 @@ PyTypeObject PyFilter_Type = {
Py_TPFLAGS_BASETYPE, /* tp_flags */
filter_doc, /* tp_doc */
filter_traverse, /* tp_traverse */
0, /* tp_clear */
filter_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
Expand Down
Loading