Summary
Fixed a critical segmentation fault bug in Python 3.13 where creating deeply nested chains of filter() iterators would crash the interpreter instead of raising a proper Python exception. The fix adds a tp_clear method to the filter object to prevent stack overflow during garbage collection of cyclic references.
Problem
When creating deeply nested filter() iterator chains (e.g., applying filter() thousands of times in a loop), Python 3.13 would crash with a segmentation fault instead of raising a RecursionError. This violates Python's fundamental principle that user code should never be able to crash the interpreter.
Example problematic code:
i = filter(bool, range(1000000))
for _ in range(100000):
i = filter(bool, i)
print(list(i)) # Segmentation fault in Python 3.13
Expected behavior: Should raise RecursionError or similar Python exception
Actual behavior: Segmentation fault (interpreter crash)
Root Cause
The filter object type in Python/bltinmodule.c was missing a tp_clear method implementation. During garbage collection of deeply nested filter iterator chains, the garbage collector would attempt to deallocate objects through recursive calls to filter_dealloc(), eventually exceeding the C stack limit and causing a segmentation fault.
Solution
Added a tp_clear method to the filter object type:
-
Implemented filter_clear() function:
static int
filter_clear(filterobject *lz)
{
Py_CLEAR(lz->it);
Py_CLEAR(lz->func);
return 0;
}
-
Updated PyFilter_Type definition:
// Changed from:
0, /* tp_clear */
// To:
(inquiry)filter_clear, /* tp_clear */
The tp_clear method allows the garbage collector to break reference cycles safely without relying on deep recursive deallocation, preventing stack overflow crashes.