|
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", |
@@ -2839,6 +2839,32 @@ def exceeds_recursion_limit(): |
2839 | 2839 | return 150_000 |
2840 | 2840 |
|
2841 | 2841 |
|
| 2842 | +def skip_if_huge_c_stack(depth=150_000): |
| 2843 | + """Skip decorator for tests which cannot overflow the C stack. |
| 2844 | +
|
| 2845 | + Tests exhausting the C stack with *depth* recursive calls cannot |
| 2846 | + trigger the recursion protection if the C stack is too large (e.g. |
| 2847 | + with a large or unlimited RLIMIT_STACK), and either fail, or run |
| 2848 | + for a very long time, or crash, or consume all memory. |
| 2849 | + """ |
| 2850 | + try: |
| 2851 | + from _testinternalcapi import get_c_recursion_remaining |
| 2852 | + except ImportError: |
| 2853 | + # Fall back to checking for an unlimited stack size. |
| 2854 | + huge = False |
| 2855 | + if not (is_emscripten or is_wasi) and os.name != "nt": |
| 2856 | + import resource |
| 2857 | + soft, hard = resource.getrlimit(resource.RLIMIT_STACK) |
| 2858 | + huge = soft == hard and soft in (-1, 0xFFFF_FFFF_FFFF_FFFF) |
| 2859 | + else: |
| 2860 | + remaining = get_c_recursion_remaining() |
| 2861 | + # A negative value means integer overflow in the estimate |
| 2862 | + # (e.g. with an unlimited RLIMIT_STACK). |
| 2863 | + huge = remaining >= depth or remaining < 0 |
| 2864 | + return unittest.skipIf( |
| 2865 | + huge, f"the C stack is large enough for {depth} recursive calls") |
| 2866 | + |
| 2867 | + |
2842 | 2868 | # Windows doesn't have os.uname() but it doesn't support s390x. |
2843 | 2869 | is_s390x = hasattr(os, 'uname') and os.uname().machine == 's390x' |
2844 | 2870 | skip_on_s390x = unittest.skipIf(is_s390x, 'skipped on s390x') |
|
0 commit comments