mirror of
https://github.com/python/cpython.git
synced 2026-01-26 21:03:34 +00:00
[3.14] gh-143460: Skip infinite recusion tests for infinite stack size (GH-143606) (#143619)
gh-143460: Skip infinite recusion tests for infinite stack size (GH-143606) Avoid tests being killed due to OOM on Linux if a system is configured with 'ulimit -s unlimited' by skipping tests relying on infinite recursion. While unclear if Python should support 'ulimit -s unlimited', we should at least try to avoid failing a PGO build running tests due to an unlimited stack size being set. (cherry picked from commit 61e036691c8ac70facb8d3fc39c670bde56218e8) Signed-off-by: Jan André Reuter <j.reuter@fz-juelich.de> Co-authored-by: Jan André Reuter <jan.andre.reuter@hotmail.de>
This commit is contained in:
parent
0e2ed4b0e1
commit
18f9af2331
@ -2267,6 +2267,7 @@ class AbstractPicklingErrorTests:
|
||||
with self.assertRaises(TypeError):
|
||||
self.dumps(c)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@no_tracing
|
||||
def test_bad_getattr(self):
|
||||
# Issue #3514: crash when there is an infinite loop in __getattr__
|
||||
|
||||
@ -44,6 +44,7 @@ __all__ = [
|
||||
"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",
|
||||
# sys
|
||||
"MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi",
|
||||
"is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval",
|
||||
@ -1684,6 +1685,25 @@ def skip_if_pgo_task(test):
|
||||
return test if ok else unittest.skip(msg)(test)
|
||||
|
||||
|
||||
def skip_if_unlimited_stack_size(test):
|
||||
"""Skip decorator for tests not run when an unlimited stack size is configured.
|
||||
|
||||
Tests using support.infinite_recursion([...]) may otherwise run into
|
||||
an infinite loop, running until the memory on the system is filled and
|
||||
crashing due to OOM.
|
||||
|
||||
See https://github.com/python/cpython/issues/143460.
|
||||
"""
|
||||
if is_wasi or os.name == "nt":
|
||||
return test
|
||||
|
||||
import resource
|
||||
curlim, maxlim = resource.getrlimit(resource.RLIMIT_STACK)
|
||||
unlimited_stack_size_cond = curlim == maxlim and curlim in (-1, 0xFFFF_FFFF_FFFF_FFFF)
|
||||
reason = "Not run due to unlimited stack size"
|
||||
return unittest.skipIf(unlimited_stack_size_cond, reason)(test)
|
||||
|
||||
|
||||
def detect_api_mismatch(ref_api, other_api, *, ignore=()):
|
||||
"""Returns the set of items in ref_api not in other_api, except for a
|
||||
defined list of items to be ignored in this check.
|
||||
|
||||
@ -24,7 +24,7 @@ except ImportError:
|
||||
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow
|
||||
from test.support import skip_emscripten_stack_overflow, skip_wasi_stack_overflow, skip_if_unlimited_stack_size
|
||||
from test.support.ast_helper import ASTTestMixin
|
||||
from test.support.import_helper import ensure_lazy_imports
|
||||
from test.test_ast.utils import to_tuple
|
||||
@ -988,6 +988,7 @@ class AST_Tests(unittest.TestCase):
|
||||
enum._test_simple_enum(_Precedence, _ast_unparse._Precedence)
|
||||
|
||||
@support.cpython_only
|
||||
@skip_if_unlimited_stack_size
|
||||
@skip_wasi_stack_overflow()
|
||||
@skip_emscripten_stack_overflow()
|
||||
def test_ast_recursion_limit(self):
|
||||
@ -1103,6 +1104,7 @@ class CopyTests(unittest.TestCase):
|
||||
ast2 = pickle.loads(pickle.dumps(tree, protocol))
|
||||
self.assertEqual(to_tuple(ast2), to_tuple(tree))
|
||||
|
||||
@skip_if_unlimited_stack_size
|
||||
def test_copy_with_parents(self):
|
||||
# gh-120108
|
||||
code = """
|
||||
@ -1951,6 +1953,7 @@ Module(
|
||||
exec(code, ns)
|
||||
self.assertIn('sleep', ns)
|
||||
|
||||
@skip_if_unlimited_stack_size
|
||||
@skip_emscripten_stack_overflow()
|
||||
def test_recursion_direct(self):
|
||||
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
|
||||
@ -1959,6 +1962,7 @@ Module(
|
||||
with support.infinite_recursion():
|
||||
compile(ast.Expression(e), "<test>", "eval")
|
||||
|
||||
@skip_if_unlimited_stack_size
|
||||
@skip_emscripten_stack_overflow()
|
||||
def test_recursion_indirect(self):
|
||||
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
|
||||
|
||||
@ -438,6 +438,7 @@ class TestPartial:
|
||||
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_emscripten_stack_overflow()
|
||||
def test_recursive_pickle(self):
|
||||
with replaced_module('functools', self.module):
|
||||
@ -2139,6 +2140,7 @@ class TestLRU:
|
||||
@support.skip_on_s390x
|
||||
@unittest.skipIf(support.is_wasi, "WASI has limited C stack")
|
||||
@support.skip_if_sanitizer("requires deep stack", ub=True, thread=True)
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
def test_lru_recursion(self):
|
||||
|
||||
|
||||
@ -317,6 +317,7 @@ class TestIsInstanceIsSubclass(unittest.TestCase):
|
||||
self.assertRaises(RecursionError, issubclass, int, X())
|
||||
self.assertRaises(RecursionError, isinstance, 1, X())
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
@support.skip_wasi_stack_overflow()
|
||||
def test_infinite_recursion_via_bases_tuple(self):
|
||||
@ -328,6 +329,7 @@ class TestIsInstanceIsSubclass(unittest.TestCase):
|
||||
with self.assertRaises(RecursionError):
|
||||
issubclass(Failure(), int)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
@support.skip_wasi_stack_overflow()
|
||||
def test_infinite_cycle_in_bases(self):
|
||||
|
||||
@ -68,6 +68,7 @@ class TestRecursion:
|
||||
self.fail("didn't raise ValueError on default recursion")
|
||||
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
@support.skip_wasi_stack_overflow()
|
||||
def test_highly_nested_objects_decoding(self):
|
||||
@ -84,6 +85,7 @@ class TestRecursion:
|
||||
with support.infinite_recursion():
|
||||
self.loads('[' * very_deep + '1' + ']' * very_deep)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_wasi_stack_overflow()
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
@support.requires_resource('cpu')
|
||||
@ -99,6 +101,7 @@ class TestRecursion:
|
||||
with support.infinite_recursion(5000):
|
||||
self.dumps(d)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
@support.skip_wasi_stack_overflow()
|
||||
def test_endless_recursion(self):
|
||||
|
||||
@ -662,6 +662,7 @@ class TestSupport(unittest.TestCase):
|
||||
""")
|
||||
script_helper.assert_python_ok("-c", code)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
def test_recursion(self):
|
||||
# Test infinite_recursion() and get_recursion_available() functions.
|
||||
def recursive_function(depth):
|
||||
|
||||
@ -93,6 +93,7 @@ class TestMiscellaneous(unittest.TestCase):
|
||||
}
|
||||
self.assertEqual(obj_copy, expected_obj)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
def test_inline_array_recursion_limit(self):
|
||||
with support.infinite_recursion(max_depth=100):
|
||||
available = support.get_recursion_available()
|
||||
@ -104,6 +105,7 @@ class TestMiscellaneous(unittest.TestCase):
|
||||
recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]"
|
||||
tomllib.loads(recursive_array_toml)
|
||||
|
||||
@support.skip_if_unlimited_stack_size
|
||||
def test_inline_table_recursion_limit(self):
|
||||
with support.infinite_recursion(max_depth=100):
|
||||
available = support.get_recursion_available()
|
||||
|
||||
@ -0,0 +1 @@
|
||||
Skip tests relying on infinite recusion if stack size is unlimited.
|
||||
Loading…
x
Reference in New Issue
Block a user