Skip to content

Commit 39b499c

Browse files
markshannonGlyphack
authored andcommitted
pythonGH-112215: Increase C recursion limit for non debug builds (pythonGH-113397)
1 parent e5430ce commit 39b499c

File tree

7 files changed

+33
-21
lines changed

7 files changed

+33
-21
lines changed

Include/cpython/pystate.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,11 @@ struct _ts {
223223
// layout, optimization, and WASI runtime. Wasmtime can handle about 700
224224
// recursions, sometimes less. 500 is a more conservative limit.
225225
# define Py_C_RECURSION_LIMIT 500
226+
#elif defined(__s390x__)
227+
# define Py_C_RECURSION_LIMIT 1200
226228
#else
227229
// This value is duplicated in Lib/test/support/__init__.py
228-
# define Py_C_RECURSION_LIMIT 1500
230+
# define Py_C_RECURSION_LIMIT 8000
229231
#endif
230232

231233

Lib/test/support/__init__.py

+8-15
Original file line numberDiff line numberDiff line change
@@ -2122,19 +2122,11 @@ def set_recursion_limit(limit):
21222122
sys.setrecursionlimit(original_limit)
21232123

21242124
def infinite_recursion(max_depth=None):
2125-
"""Set a lower limit for tests that interact with infinite recursions
2126-
(e.g test_ast.ASTHelpers_Test.test_recursion_direct) since on some
2127-
debug windows builds, due to not enough functions being inlined the
2128-
stack size might not handle the default recursion limit (1000). See
2129-
bpo-11105 for details."""
21302125
if max_depth is None:
2131-
if not python_is_optimized() or Py_DEBUG:
2132-
# Python built without compiler optimizations or in debug mode
2133-
# usually consumes more stack memory per function call.
2134-
# Unoptimized number based on what works under a WASI debug build.
2135-
max_depth = 50
2136-
else:
2137-
max_depth = 100
2126+
# Pick a number large enough to cause problems
2127+
# but not take too long for code that can handle
2128+
# very deep recursion.
2129+
max_depth = 20_000
21382130
elif max_depth < 3:
21392131
raise ValueError("max_depth must be at least 3, got {max_depth}")
21402132
depth = get_recursion_depth()
@@ -2373,20 +2365,21 @@ def adjust_int_max_str_digits(max_digits):
23732365
finally:
23742366
sys.set_int_max_str_digits(current)
23752367

2376-
#For recursion tests, easily exceeds default recursion limit
2377-
EXCEEDS_RECURSION_LIMIT = 5000
23782368

23792369
def _get_c_recursion_limit():
23802370
try:
23812371
import _testcapi
23822372
return _testcapi.Py_C_RECURSION_LIMIT
23832373
except (ImportError, AttributeError):
23842374
# Originally taken from Include/cpython/pystate.h .
2385-
return 1500
2375+
return 8000
23862376

23872377
# The default C recursion limit.
23882378
Py_C_RECURSION_LIMIT = _get_c_recursion_limit()
23892379

2380+
#For recursion tests, easily exceeds default recursion limit
2381+
EXCEEDS_RECURSION_LIMIT = Py_C_RECURSION_LIMIT * 3
2382+
23902383
#Windows doesn't have os.uname() but it doesn't support s390x.
23912384
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
23922385
'skipped on s390x')

Lib/test/test_functools.py

+14
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,20 @@ def orig(): ...
18621862
self.assertEqual(str(Signature.from_callable(lru.cache_info)), '()')
18631863
self.assertEqual(str(Signature.from_callable(lru.cache_clear)), '()')
18641864

1865+
@support.skip_on_s390x
1866+
@unittest.skipIf(support.is_wasi, "WASI has limited C stack")
1867+
def test_lru_recursion(self):
1868+
1869+
@self.module.lru_cache
1870+
def fib(n):
1871+
if n <= 1:
1872+
return n
1873+
return fib(n-1) + fib(n-2)
1874+
1875+
if not support.Py_DEBUG:
1876+
with support.infinite_recursion():
1877+
fib(2500)
1878+
18651879

18661880
@py_functools.lru_cache()
18671881
def py_cached_func(x, y):

Lib/test/test_json/test_recursion.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ def test_highly_nested_objects_encoding(self):
8585
for x in range(100000):
8686
l, d = [l], {'k':d}
8787
with self.assertRaises(RecursionError):
88-
with support.infinite_recursion():
88+
with support.infinite_recursion(5000):
8989
self.dumps(l)
9090
with self.assertRaises(RecursionError):
91-
with support.infinite_recursion():
91+
with support.infinite_recursion(5000):
9292
self.dumps(d)
9393

9494
def test_endless_recursion(self):
@@ -99,7 +99,7 @@ def default(self, o):
9999
return [o]
100100

101101
with self.assertRaises(RecursionError):
102-
with support.infinite_recursion():
102+
with support.infinite_recursion(1000):
103103
EndlessJSONEncoder(check_circular=False).encode(5j)
104104

105105

Lib/test/test_support.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ def recursive_function(depth):
630630
if depth:
631631
recursive_function(depth - 1)
632632

633-
for max_depth in (5, 25, 250):
633+
for max_depth in (5, 25, 250, 2500):
634634
with support.infinite_recursion(max_depth):
635635
available = support.get_recursion_available()
636636

Lib/test/test_xml_etree.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2535,7 +2535,7 @@ def __eq__(self, o):
25352535
e.extend([ET.Element('bar')])
25362536
self.assertRaises(ValueError, e.remove, X('baz'))
25372537

2538-
@support.infinite_recursion(25)
2538+
@support.infinite_recursion()
25392539
def test_recursive_repr(self):
25402540
# Issue #25455
25412541
e = ET.Element('foo')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Increase the C recursion limit by a factor of 3 for non-debug builds, except
2+
for webassembly and s390 platforms which are unchanged. This mitigates some
3+
regressions in 3.12 with deep recursion mixing builtin (C) and Python code.

0 commit comments

Comments
 (0)