|
45 | 45 | "check__all__", "skip_if_buggy_ucrt_strfptime", |
46 | 46 | "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", |
47 | 47 | "requires_limited_api", "requires_specialization", "thread_unsafe", |
48 | | - "skip_if_unlimited_stack_size", |
| 48 | + "skip_if_unlimited_stack_size", "skip_if_huge_c_stack", |
49 | 49 | # sys |
50 | 50 | "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", |
51 | 51 | "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", |
@@ -2827,6 +2827,32 @@ def exceeds_recursion_limit(): |
2827 | 2827 | return 150_000 |
2828 | 2828 |
|
2829 | 2829 |
|
| 2830 | +def skip_if_huge_c_stack(depth=150_000): |
| 2831 | + """Skip decorator for tests which cannot overflow the C stack. |
| 2832 | +
|
| 2833 | + Tests exhausting the C stack with *depth* recursive calls cannot |
| 2834 | + trigger the recursion protection if the C stack is too large (e.g. |
| 2835 | + with a large or unlimited RLIMIT_STACK), and either fail, or run |
| 2836 | + for a very long time, or crash, or consume all memory. |
| 2837 | + """ |
| 2838 | + try: |
| 2839 | + from _testinternalcapi import get_c_recursion_remaining |
| 2840 | + except ImportError: |
| 2841 | + # Fall back to checking for an unlimited stack size. |
| 2842 | + huge = False |
| 2843 | + if not (is_emscripten or is_wasi) and os.name != "nt": |
| 2844 | + import resource |
| 2845 | + soft, hard = resource.getrlimit(resource.RLIMIT_STACK) |
| 2846 | + huge = soft == hard and soft in (-1, 0xFFFF_FFFF_FFFF_FFFF) |
| 2847 | + else: |
| 2848 | + remaining = get_c_recursion_remaining() |
| 2849 | + # A negative value means integer overflow in the estimate |
| 2850 | + # (e.g. with an unlimited RLIMIT_STACK). |
| 2851 | + huge = remaining >= depth or remaining < 0 |
| 2852 | + return unittest.skipIf( |
| 2853 | + huge, f"the C stack is large enough for {depth} recursive calls") |
| 2854 | + |
| 2855 | + |
2830 | 2856 | # Windows doesn't have os.uname() but it doesn't support s390x. |
2831 | 2857 | is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x' |
2832 | 2858 | skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x') |
|
0 commit comments