from functools import cmp_to_key
from test import seq_tests
-from test.support import ALWAYS_EQ, NEVER_EQ
+from test.support import ALWAYS_EQ, NEVER_EQ, skip_if_huge_c_stack
from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow
self.assertEqual(str(a2), "[0, 1, 2, [...], 3]")
self.assertEqual(repr(a2), "[0, 1, 2, [...], 3]")
+ @skip_if_huge_c_stack(200_000)
@skip_wasi_stack_overflow()
@skip_emscripten_stack_overflow()
def test_repr_deep(self):
d = self._full_mapping({1: BadRepr()})
self.assertRaises(Exc, repr, d)
+ @support.skip_if_huge_c_stack()
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
@support.skip_if_sanitizer("requires deep stack", ub=True)
"check__all__", "skip_if_buggy_ucrt_strfptime",
"check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
"requires_limited_api", "requires_specialization", "thread_unsafe",
- "skip_if_unlimited_stack_size",
+ "skip_if_unlimited_stack_size", "skip_if_huge_c_stack",
# sys
"MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi",
"is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval",
return 150_000
+def skip_if_huge_c_stack(depth=150_000):
+ """Skip decorator for tests which cannot overflow the C stack.
+
+ Tests exhausting the C stack with *depth* recursive calls cannot
+ trigger the recursion protection if the C stack is too large (e.g.
+ with a large or unlimited RLIMIT_STACK), and either fail, or run
+ for a very long time, or crash, or consume all memory.
+ """
+ try:
+ from _testinternalcapi import get_c_recursion_remaining
+ except ImportError:
+ # Fall back to checking for an unlimited stack size.
+ huge = False
+ if not (is_emscripten or is_wasi) and os.name != "nt":
+ import resource
+ soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
+ huge = soft == hard and soft in (-1, 0xFFFF_FFFF_FFFF_FFFF)
+ else:
+ remaining = get_c_recursion_remaining()
+ # A negative value means integer overflow in the estimate
+ # (e.g. with an unlimited RLIMIT_STACK).
+ huge = remaining >= depth or remaining < 0
+ return unittest.skipIf(
+ huge, f"the C stack is large enough for {depth} recursive calls")
+
+
# Windows doesn't have os.uname() but it doesn't support s390x.
is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x'
skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x')
from test import support
from test.support import os_helper
-from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, skip_if_unlimited_stack_size
+from test.support import (skip_emscripten_stack_overflow,
+ skip_wasi_stack_overflow,
+ skip_if_unlimited_stack_size, skip_if_huge_c_stack)
from test.support.ast_helper import ASTTestMixin
from test.support.import_helper import ensure_lazy_imports
from test.test_ast.utils import to_tuple
enum._test_simple_enum(_Precedence, _ast_unparse._Precedence)
@support.cpython_only
- @skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack(100_000 if sys.platform == "android" else 500_000)
@skip_wasi_stack_overflow()
@skip_emscripten_stack_overflow()
def test_ast_recursion_limit(self):
exec(code, ns)
self.assertIn('sleep', ns)
- @skip_if_unlimited_stack_size
+ @skip_if_huge_c_stack()
@skip_emscripten_stack_overflow()
def test_recursion_direct(self):
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
with support.infinite_recursion():
compile(ast.Expression(e), "<test>", "eval")
- @skip_if_unlimited_stack_size
+ @skip_if_huge_c_stack()
@skip_emscripten_stack_overflow()
def test_recursion_indirect(self):
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
set_recursion_limit, skip_on_s390x,
skip_emscripten_stack_overflow,
skip_wasi_stack_overflow, skip_if_sanitizer,
- import_helper)
+ skip_if_huge_c_stack, import_helper)
try:
import _testcapi
except ImportError:
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
@skip_if_sanitizer("requires deep stack", thread=True)
@unittest.skipIf(_testcapi is None, "requires _testcapi")
+ @skip_if_huge_c_stack(90_000)
@skip_emscripten_stack_overflow()
@skip_wasi_stack_overflow()
def test_super_deep(self):
self.assertFalse(hasattr(o, "__call__"))
self.assertFalse(hasattr(c, "__call__"))
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def testSFBug532646(self):
@support.cpython_only
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
+ @support.skip_if_huge_c_stack(100_000 if sys.platform == "android" else 500_000)
@support.skip_emscripten_stack_overflow()
def test_compiler_recursion_limit(self):
# Compiler frames are small
self.assertIsNot(x, y)
self.assertIsNot(x[0], y[0])
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_deepcopy_reflexive_list(self):
y = copy.deepcopy(x)
self.assertIs(x, y)
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_deepcopy_reflexive_tuple(self):
self.assertIsNot(x[0], y[0])
self.assertIs(y[0]['foo'], y)
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_deepcopy_reflexive_dict(self):
self.assertIsNot(y, x)
self.assertIsNot(y.foo, x.foo)
+ @support.skip_if_huge_c_stack()
def test_deepcopy_reflexive_inst(self):
class C:
pass
self.assertEqual(y, x)
self.assertIsNot(y.foo, x.foo)
+ @support.skip_if_huge_c_stack()
def test_reconstruct_reflexive(self):
class C(object):
pass
c_short, c_int, c_long, c_longlong,
c_byte, c_wchar, c_float, c_double,
ArgumentError)
-from test.support import import_helper, skip_if_sanitizer, skip_emscripten_stack_overflow
+from test.support import (import_helper, skip_if_sanitizer,
+ skip_emscripten_stack_overflow, skip_if_huge_c_stack)
_ctypes_test = import_helper.import_module("_ctypes_test")
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
@skip_if_sanitizer('requires deep stack', thread=True)
+ @skip_if_huge_c_stack()
@skip_emscripten_stack_overflow()
def test_recursive_as_param(self):
class A:
encoding='latin1', errors='replace')
self.assertEqual(ba, b'abc\xbd?')
+ @support.skip_if_huge_c_stack()
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
def test_recursive_call(self):
# CALL_METHOD_DESCRIPTOR_O
deque.append(thing, thing)
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_repr_as_str(self):
d = {1: BadRepr()}
self.assertRaises(Exc, repr, d)
+ @support.skip_if_huge_c_stack()
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
def test_repr_deep(self):
import copy
import pickle
import unittest
-from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit
+from test.support import (skip_emscripten_stack_overflow,
+ skip_wasi_stack_overflow, skip_if_huge_c_stack,
+ exceeds_recursion_limit)
class DictSetTest(unittest.TestCase):
# Again.
self.assertIsInstance(r, str)
+ @skip_if_huge_c_stack()
@skip_wasi_stack_overflow()
@skip_emscripten_stack_overflow()
def test_deeply_nested_repr(self):
import collections
import types
import unittest
-from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, exceeds_recursion_limit
+from test.support import (skip_emscripten_stack_overflow,
+ skip_wasi_stack_overflow, skip_if_huge_c_stack,
+ exceeds_recursion_limit)
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
def test_exception_group_types(self):
e = ExceptionGroup('eg', [e])
return e
+ @skip_if_huge_c_stack()
@skip_emscripten_stack_overflow()
@skip_wasi_stack_overflow()
def test_deep_split(self):
with self.assertRaises(RecursionError):
e.split(TypeError)
+ @skip_if_huge_c_stack()
@skip_emscripten_stack_overflow()
@skip_wasi_stack_overflow()
def test_deep_subgroup(self):
@cpython_only
@unittest.skipIf(_testcapi is None, "requires _testcapi")
@force_not_colorized
+ @support.skip_if_huge_c_stack()
def test_recursion_normalizing_infinite_exception(self):
# Issue #30697. Test that a RecursionError is raised when
# maximum recursion depth has been exceeded when creating
self.assertIs(type(r[0]), tuple)
@support.skip_if_sanitizer("thread sanitizer crashes in __tsan::FuncEntry", thread=True)
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
def test_recursive_pickle(self):
with replaced_module('functools', self.module):
self.assertEqual(True, issubclass(int, (int, (float, int))))
self.assertEqual(True, issubclass(str, (str, (Child, str))))
+ @support.skip_if_huge_c_stack()
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
def test_subclass_recursion_limit(self):
# blown
self.assertRaises(RecursionError, blowstack, issubclass, str, str)
+ @support.skip_if_huge_c_stack()
@support.skip_wasi_stack_overflow()
@support.skip_emscripten_stack_overflow()
def test_isinstance_recursion_limit(self):
self.assertRaises(RecursionError, issubclass, int, X())
self.assertRaises(RecursionError, isinstance, 1, X())
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_infinite_recursion_via_bases_tuple(self):
with self.assertRaises(RecursionError):
issubclass(Failure(), int)
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_infinite_cycle_in_bases(self):
@support.skip_if_pgo_task # fails during PGO training w/ some stack sizes
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack(500_000)
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_highly_nested_objects_decoding(self):
with support.infinite_recursion(5000):
self.dumps(d)
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_endless_recursion(self):
parser.ElementDeclHandler = lambda _1, _2: None
self.assertRaises(TypeError, parser.Parse, data, True)
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack(800_000)
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_deeply_nested_content_model(self):
self.assertEqual([c.tag for c in children[3:]],
[a.tag, b.tag, a.tag, b.tag])
- @support.skip_if_unlimited_stack_size
+ @support.skip_if_huge_c_stack(500_000)
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_deeply_nested_deepcopy(self):
--- /dev/null
+Add ``test.support.skip_if_huge_c_stack()`` and use it to skip tests
+that exhaust the C stack if the stack limit is very large
+(e.g. on DragonFly BSD or with ``ulimit -s unlimited``).