Files
micropython/tests/stress/recursive_iternext.py
Angus Gratton 22deeeb8db tests/stress/recursive_iternext: Rewrite to find its own limit.
Necessary on the unix port when running with sanitizers, as the newly
increased stack size can run all tests at N=5000 without raising
RuntimeError, and increasing N to fix this causes issues on other
configurations.

This way the test progressively builds a deeper data structure until it
fails with RuntimeError. This is theoretically slower, but not noticeably
so in reality.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2025-08-19 10:33:40 +10:00

38 lines
1.1 KiB
Python

# This tests that recursion with iternext doesn't lead to segfault.
#
# This test segfaults CPython, but that's not a bug as CPython doesn't enforce
# limits on C recursion - see
# https://github.com/python/cpython/issues/58218#issuecomment-1093570209
try:
enumerate
filter
map
max
zip
except:
print("SKIP")
raise SystemExit
# Progressively build a bigger nested iterator structure (10 at a time for speed),
# and then try to evaluate it via tuple(x) which makes deep recursive function calls.
#
# Eventually this should raise a RuntimeError as MicroPython runs out of stack.
# It shouldn't ever raise a MemoryError, if it does then somehow MicroPython has
# run out of heap (for the nested structure) before running out of stack.
def recurse_iternext(nested_fn):
x = (1, 2)
while True:
for _ in range(10):
x = nested_fn(x)
try:
tuple(x)
except RuntimeError:
print("RuntimeError")
break
# Test on various nested iterator structures
for nested_fn in [enumerate, lambda x: filter(None, x), lambda x: map(max, x, ()), zip]:
recurse_iternext(nested_fn)