]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-112215: Increase C recursion limit for non debug builds (GH-113397)
authorMark Shannon <mark@hotpy.org>
Fri, 22 Dec 2023 14:25:25 +0000 (14:25 +0000)
committerGitHub <noreply@github.com>
Fri, 22 Dec 2023 14:25:25 +0000 (14:25 +0000)
Include/cpython/pystate.h
Lib/test/support/__init__.py
Lib/test/test_functools.py
Lib/test/test_json/test_recursion.py
Lib/test/test_support.py
Lib/test/test_xml_etree.py
Misc/NEWS.d/next/Core and Builtins/2023-12-15-16-26-01.gh-issue-112215.xJS6_6.rst [new file with mode: 0644]

index 56172d231c44f4e9ea442ba068f2f080827215f1..ed7dd829d4b6f0dd6c918d323d1e304741ec0ef3 100644 (file)
@@ -223,9 +223,11 @@ struct _ts {
    // layout, optimization, and WASI runtime. Wasmtime can handle about 700
    // recursions, sometimes less. 500 is a more conservative limit.
 #  define Py_C_RECURSION_LIMIT 500
+#elif defined(__s390x__)
+#  define Py_C_RECURSION_LIMIT 1200
 #else
    // This value is duplicated in Lib/test/support/__init__.py
-#  define Py_C_RECURSION_LIMIT 1500
+#  define Py_C_RECURSION_LIMIT 8000
 #endif
 
 
index b605951320dc8b6bd06543b90f27f56e3bda711d..c8f73cede230d8348aef66ba49b5e755b56083ce 100644 (file)
@@ -2122,19 +2122,11 @@ def set_recursion_limit(limit):
         sys.setrecursionlimit(original_limit)
 
 def infinite_recursion(max_depth=None):
-    """Set a lower limit for tests that interact with infinite recursions
-    (e.g test_ast.ASTHelpers_Test.test_recursion_direct) since on some
-    debug windows builds, due to not enough functions being inlined the
-    stack size might not handle the default recursion limit (1000). See
-    bpo-11105 for details."""
     if max_depth is None:
-        if not python_is_optimized() or Py_DEBUG:
-            # Python built without compiler optimizations or in debug mode
-            # usually consumes more stack memory per function call.
-            # Unoptimized number based on what works under a WASI debug build.
-            max_depth = 50
-        else:
-            max_depth = 100
+        # Pick a number large enough to cause problems
+        # but not take too long for code that can handle
+        # very deep recursion.
+        max_depth = 20_000
     elif max_depth < 3:
         raise ValueError("max_depth must be at least 3, got {max_depth}")
     depth = get_recursion_depth()
@@ -2373,8 +2365,6 @@ def adjust_int_max_str_digits(max_digits):
     finally:
         sys.set_int_max_str_digits(current)
 
-#For recursion tests, easily exceeds default recursion limit
-EXCEEDS_RECURSION_LIMIT = 5000
 
 def _get_c_recursion_limit():
     try:
@@ -2382,11 +2372,14 @@ def _get_c_recursion_limit():
         return _testcapi.Py_C_RECURSION_LIMIT
     except (ImportError, AttributeError):
         # Originally taken from Include/cpython/pystate.h .
-        return 1500
+        return 8000
 
 # The default C recursion limit.
 Py_C_RECURSION_LIMIT = _get_c_recursion_limit()
 
+#For recursion tests, easily exceeds default recursion limit
+EXCEEDS_RECURSION_LIMIT = Py_C_RECURSION_LIMIT * 3
+
 #Windows doesn't have os.uname() but it doesn't support s390x.
 skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
                                 'skipped on s390x')
index e4de2c5ede15f1da4990ec8e9f4cec9a05f9c698..b95afe0bcc86e467c6e373e4670c87c09930e193 100644 (file)
@@ -1862,6 +1862,20 @@ class TestLRU:
         self.assertEqual(str(Signature.from_callable(lru.cache_info)), '()')
         self.assertEqual(str(Signature.from_callable(lru.cache_clear)), '()')
 
+    @support.skip_on_s390x
+    @unittest.skipIf(support.is_wasi, "WASI has limited C stack")
+    def test_lru_recursion(self):
+
+        @self.module.lru_cache
+        def fib(n):
+            if n <= 1:
+                return n
+            return fib(n-1) + fib(n-2)
+
+        if not support.Py_DEBUG:
+            with support.infinite_recursion():
+                fib(2500)
+
 
 @py_functools.lru_cache()
 def py_cached_func(x, y):
index 9919d7fbe54ef7492e47db525fc55dd7188f3226..164ff2013eb552c4acadc4f86761ee0c6d577e84 100644 (file)
@@ -85,10 +85,10 @@ class TestRecursion:
         for x in range(100000):
             l, d = [l], {'k':d}
         with self.assertRaises(RecursionError):
-            with support.infinite_recursion():
+            with support.infinite_recursion(5000):
                 self.dumps(l)
         with self.assertRaises(RecursionError):
-            with support.infinite_recursion():
+            with support.infinite_recursion(5000):
                 self.dumps(d)
 
     def test_endless_recursion(self):
@@ -99,7 +99,7 @@ class TestRecursion:
                 return [o]
 
         with self.assertRaises(RecursionError):
-            with support.infinite_recursion():
+            with support.infinite_recursion(1000):
                 EndlessJSONEncoder(check_circular=False).encode(5j)
 
 
index c34b0e5e015702021ea5c2d747f93f1bd2be4d0d..d160cbf0645b47f05b884662660a51fb2bc715e1 100644 (file)
@@ -630,7 +630,7 @@ class TestSupport(unittest.TestCase):
             if depth:
                 recursive_function(depth - 1)
 
-        for max_depth in (5, 25, 250):
+        for max_depth in (5, 25, 250, 2500):
             with support.infinite_recursion(max_depth):
                 available = support.get_recursion_available()
 
index b9e7937b0bbc00a5163632269f3cc9e2e9d90272..80ee064896f59a363f29bf503ae8435333b84b0b 100644 (file)
@@ -2535,7 +2535,7 @@ class BadElementTest(ElementTestCase, unittest.TestCase):
         e.extend([ET.Element('bar')])
         self.assertRaises(ValueError, e.remove, X('baz'))
 
-    @support.infinite_recursion(25)
+    @support.infinite_recursion()
     def test_recursive_repr(self):
         # Issue #25455
         e = ET.Element('foo')
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-15-16-26-01.gh-issue-112215.xJS6_6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-15-16-26-01.gh-issue-112215.xJS6_6.rst
new file mode 100644 (file)
index 0000000..01ca1cc
--- /dev/null
@@ -0,0 +1,3 @@
+Increase the C recursion limit by a factor of 3 for non-debug builds, except
+for webassembly and s390 platforms which are unchanged. This mitigates some
+regressions in 3.12 with deep recursion mixing builtin (C) and Python code.