summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-10-05 00:34:03 (GMT)
committerGitHub <noreply@github.com>2022-10-05 00:34:03 (GMT)
commit76449350b3467b85bcb565f9e2bf945bd150a66e (patch)
treee4237841cdb9d9984e3249823a8518c79470d73f /Lib
parent0ff8fd65838f9f9ed90d7a055d26a2ce9fc0ce85 (diff)
downloadcpython-76449350b3467b85bcb565f9e2bf945bd150a66e.zip
cpython-76449350b3467b85bcb565f9e2bf945bd150a66e.tar.gz
cpython-76449350b3467b85bcb565f9e2bf945bd150a66e.tar.bz2
GH-91079: Decouple C stack overflow checks from Python recursion checks. (GH-96510)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/support/__init__.py5
-rw-r--r--Lib/test/test_ast.py6
-rw-r--r--Lib/test/test_call.py38
-rw-r--r--Lib/test/test_collections.py2
-rw-r--r--Lib/test/test_compile.py3
-rw-r--r--Lib/test/test_dynamic.py8
-rw-r--r--Lib/test/test_exceptions.py8
-rw-r--r--Lib/test/test_isinstance.py12
-rw-r--r--Lib/test/test_marshal.py3
9 files changed, 61 insertions, 24 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 573dce5..9fdad64 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -60,7 +60,7 @@ __all__ = [
"run_with_tz", "PGO", "missing_compiler_executable",
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
- "Py_DEBUG",
+ "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT",
]
@@ -2352,3 +2352,6 @@ def adjust_int_max_str_digits(max_digits):
yield
finally:
sys.set_int_max_str_digits(current)
+
+#For recursion tests, easily exceeds default recursion limit
+EXCEEDS_RECURSION_LIMIT = 5000
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 9a7df28..b346441 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -825,9 +825,9 @@ class AST_Tests(unittest.TestCase):
@support.cpython_only
def test_ast_recursion_limit(self):
- fail_depth = sys.getrecursionlimit() * 3
- crash_depth = sys.getrecursionlimit() * 300
- success_depth = int(fail_depth * 0.75)
+ fail_depth = support.EXCEEDS_RECURSION_LIMIT
+ crash_depth = 100_000
+ success_depth = 1200
def check_limit(prefix, repeated):
expect_ok = prefix + repeated * success_depth
diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py
index c1a3862..1f3307f 100644
--- a/Lib/test/test_call.py
+++ b/Lib/test/test_call.py
@@ -864,6 +864,44 @@ class TestErrorMessagesUseQualifiedName(unittest.TestCase):
with self.check_raises_type_error(msg):
A().method_two_args("x", "y", x="oops")
+@cpython_only
+class TestRecursion(unittest.TestCase):
+
+ def test_super_deep(self):
+
+ def recurse(n):
+ if n:
+ recurse(n-1)
+
+ def py_recurse(n, m):
+ if n:
+ py_recurse(n-1, m)
+ else:
+ c_py_recurse(m-1)
+
+ def c_recurse(n):
+ if n:
+ _testcapi.pyobject_fastcall(c_recurse, (n-1,))
+
+ def c_py_recurse(m):
+ if m:
+ _testcapi.pyobject_fastcall(py_recurse, (1000, m))
+
+ depth = sys.getrecursionlimit()
+ sys.setrecursionlimit(100_000)
+ try:
+ recurse(90_000)
+ with self.assertRaises(RecursionError):
+ recurse(101_000)
+ c_recurse(100)
+ with self.assertRaises(RecursionError):
+ c_recurse(90_000)
+ c_py_recurse(90)
+ with self.assertRaises(RecursionError):
+ c_py_recurse(100_000)
+ finally:
+ sys.setrecursionlimit(depth)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 59b3f2e..1e398d6 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -545,7 +545,7 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(Dot(1)._replace(d=999), (999,))
self.assertEqual(Dot(1)._fields, ('d',))
- n = 5000
+ n = support.EXCEEDS_RECURSION_LIMIT
names = list(set(''.join([choice(string.ascii_letters)
for j in range(10)]) for i in range(n)))
n = len(names)
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 7c55c71..21dcc1a 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -111,8 +111,7 @@ class TestSpecifics(unittest.TestCase):
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
def test_extended_arg(self):
- # default: 1000 * 2.5 = 2500 repetitions
- repeat = int(sys.getrecursionlimit() * 2.5)
+ repeat = 2000
longexpr = 'x = x or ' + '-x' * repeat
g = {}
code = '''
diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py
index 25544de..7e12d42 100644
--- a/Lib/test/test_dynamic.py
+++ b/Lib/test/test_dynamic.py
@@ -140,11 +140,11 @@ class RebindBuiltinsTests(unittest.TestCase):
def __missing__(self, key):
return int(key.removeprefix("_number_"))
- # 1,000 on most systems
- limit = sys.getrecursionlimit()
- code = "lambda: " + "+".join(f"_number_{i}" for i in range(limit))
+ # Need more than 256 variables to use EXTENDED_ARGS
+ variables = 400
+ code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables))
sum_func = eval(code, MyGlobals())
- expected = sum(range(limit))
+ expected = sum(range(variables))
# Warm up the the function for quickening (PEP 659)
for _ in range(30):
self.assertEqual(sum_func(), expected)
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 03a0f8b..65a3a8a 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -1372,6 +1372,7 @@ class ExceptionTests(unittest.TestCase):
code = """if 1:
import sys
from _testinternalcapi import get_recursion_depth
+ from test import support
class MyException(Exception): pass
@@ -1399,13 +1400,8 @@ class ExceptionTests(unittest.TestCase):
generator = gen()
next(generator)
recursionlimit = sys.getrecursionlimit()
- depth = get_recursion_depth()
try:
- # Upon the last recursive invocation of recurse(),
- # tstate->recursion_depth is equal to (recursion_limit - 1)
- # and is equal to recursion_limit when _gen_throw() calls
- # PyErr_NormalizeException().
- recurse(setrecursionlimit(depth + 2) - depth)
+ recurse(support.EXCEEDS_RECURSION_LIMIT)
finally:
sys.setrecursionlimit(recursionlimit)
print('Done.')
diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py
index a097464..2fcf6eb 100644
--- a/Lib/test/test_isinstance.py
+++ b/Lib/test/test_isinstance.py
@@ -8,7 +8,7 @@ import typing
from test import support
-
+
class TestIsInstanceExceptions(unittest.TestCase):
# Test to make sure that an AttributeError when accessing the instance's
# class's bases is masked. This was actually a bug in Python 2.2 and
@@ -97,7 +97,7 @@ class TestIsInstanceExceptions(unittest.TestCase):
class D: pass
self.assertRaises(RuntimeError, isinstance, c, D)
-
+
# These tests are similar to above, but tickle certain code paths in
# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
# vs. PyObject_IsInstance().
@@ -147,7 +147,7 @@ class TestIsSubclassExceptions(unittest.TestCase):
self.assertRaises(TypeError, issubclass, B, C())
-
+
# meta classes for creating abstract classes and instances
class AbstractClass(object):
def __init__(self, bases):
@@ -179,7 +179,7 @@ class Super:
class Child(Super):
pass
-
+
class TestIsInstanceIsSubclass(unittest.TestCase):
# Tests to ensure that isinstance and issubclass work on abstract
# classes and instances. Before the 2.2 release, TypeErrors were
@@ -353,10 +353,10 @@ def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its
# argument will raise RecursionError eventually.
tuple_arg = (compare_to,)
- for cnt in range(sys.getrecursionlimit()+5):
+ for cnt in range(support.EXCEEDS_RECURSION_LIMIT):
tuple_arg = (tuple_arg,)
fxn(arg, tuple_arg)
-
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index 882a819..fe4f368 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -117,7 +117,8 @@ class CodeTestCase(unittest.TestCase):
def test_many_codeobjects(self):
# Issue2957: bad recursion count on code objects
- count = 5000 # more than MAX_MARSHAL_STACK_DEPTH
+ # more than MAX_MARSHAL_STACK_DEPTH
+ count = support.EXCEEDS_RECURSION_LIMIT
codes = (ExceptionTestCase.test_exceptions.__code__,) * count
marshal.loads(marshal.dumps(codes))