GH-113655: Lower the C recursion limit on various platforms (GH-113944) · python/cpython@17b73ab

GitHub

File tree

Include/cpython

Lib/test

support

Misc/NEWS.d/next/Core and Builtins

Parser

Python

Original file line numberDiff line numberDiff line change@@ -224,10 +224,14 @@ struct _ts {

224224// recursions, sometimes less. 500 is a more conservative limit.

225225# definePy_C_RECURSION_LIMIT 500

226226#elif defined(__s390x__)

227-# definePy_C_RECURSION_LIMIT 1200

227+# definePy_C_RECURSION_LIMIT 800

228+#elif defined(_WIN32)

229+# definePy_C_RECURSION_LIMIT 4000

230+#elif defined(_Py_ADDRESS_SANITIZER)

231+# definePy_C_RECURSION_LIMIT 4000

228232#else

229233// This value is duplicated in Lib/test/support/__init__.py

230-# definePy_C_RECURSION_LIMIT8000

234+# definePy_C_RECURSION_LIMIT10000

231235#endif

232236233237Original file line numberDiff line numberDiff line change@@ -2377,7 +2377,10 @@ def _get_c_recursion_limit():

23772377return_testcapi.Py_C_RECURSION_LIMIT

23782378except (ImportError, AttributeError):

23792379# Originally taken from Include/cpython/pystate.h .

2380-return8000

2380+ifsys.platform=='win32':

2381+return4000

2382+else:

2383+return10000

2381238423822385# The default C recursion limit.

23832386Py_C_RECURSION_LIMIT=_get_c_recursion_limit()

Original file line numberDiff line numberDiff line change@@ -1126,7 +1126,7 @@ def next(self):

11261126deftest_ast_recursion_limit(self):

11271127fail_depth=support.EXCEEDS_RECURSION_LIMIT

11281128crash_depth=100_000

1129-success_depth=1200

1129+success_depth=int(support.Py_C_RECURSION_LIMIT*0.8)

11301130if_testinternalcapiisnotNone:

11311131remaining=_testinternalcapi.get_c_recursion_remaining()

11321132success_depth=min(success_depth, remaining)

Original file line numberDiff line numberDiff line change@@ -623,12 +623,10 @@ def test_yet_more_evil_still_undecodable(self):

[email protected]_only

[email protected](support.is_wasi, "exhausts limited stack on WASI")

625625deftest_compiler_recursion_limit(self):

626-# Expected limit is Py_C_RECURSION_LIMIT * 2

627-# Duplicating the limit here is a little ugly.

628-# Perhaps it should be exposed somewhere...

629-fail_depth=Py_C_RECURSION_LIMIT*2+1

626+# Expected limit is Py_C_RECURSION_LIMIT

627+fail_depth=Py_C_RECURSION_LIMIT+1

630628crash_depth=Py_C_RECURSION_LIMIT*100

631-success_depth=int(Py_C_RECURSION_LIMIT*1.8)

629+success_depth=int(Py_C_RECURSION_LIMIT*0.8)

632630633631defcheck_limit(prefix, repeated, mode="single"):

634632expect_ok=prefix+repeated*success_depth

Original file line numberDiff line numberDiff line change@@ -1875,8 +1875,14 @@ def fib(n):

18751875returnfib(n-1) +fib(n-2)

1876187618771877ifnotsupport.Py_DEBUG:

1878+depth=support.Py_C_RECURSION_LIMIT*2//7

18781879withsupport.infinite_recursion():

1879-fib(2500)

1880+fib(depth)

1881+ifself.module==c_functools:

1882+fib.cache_clear()

1883+withsupport.infinite_recursion():

1884+withself.assertRaises(RecursionError):

1885+fib(10000)

188018861881188718821888@py_functools.lru_cache()

Original file line numberDiff line numberDiff line change@@ -3037,10 +3037,8 @@ def test_trace_unpack_long_sequence(self):

30373037self.assertEqual(counts, {'call': 1, 'line': 301, 'return': 1})

3038303830393039deftest_trace_lots_of_globals(self):

3040-count=1000

3041-if_testinternalcapiisnotNone:

3042-remaining=_testinternalcapi.get_c_recursion_remaining()

3043-count=min(count, remaining)

3040+3041+count=min(1000, int(support.Py_C_RECURSION_LIMIT*0.8))

3044304230453043code="""if 1:

30463044 def f():

Original file line numberDiff line numberDiff line change@@ -0,0 +1,3 @@

1+Set the C recursion limit to 4000 on Windows, and 10000 on Linux/OSX. This

2+seems to be near the sweet spot to maintain safety, but not compromise

3+backwards compatibility.

Original file line numberDiff line numberDiff line change@@ -1388,15 +1388,14 @@ class PartingShots(StaticVisitor):

1388138813891389 int starting_recursion_depth;

13901390 /* Be careful here to prevent overflow. */

1391- int COMPILER_STACK_FRAME_SCALE = 2;

13921391 PyThreadState *tstate = _PyThreadState_GET();

13931392 if (!tstate) {

13941393 return NULL;

13951394 }

13961395 struct validator vstate;

1397- vstate.recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;

1396+ vstate.recursion_limit = Py_C_RECURSION_LIMIT;

13981397 int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;

1399- starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;

1398+ starting_recursion_depth = recursion_depth;

14001399 vstate.recursion_depth = starting_recursion_depth;

1401140014021401 PyObject *result = ast2obj_mod(state, &vstate, t);

Original file line numberDiff line numberDiff line change@@ -1037,10 +1037,6 @@ validate_type_params(struct validator *state, asdl_type_param_seq *tps)

10371037return1;

10381038}

103910391040-1041-/* See comments in symtable.c. */

1042-#defineCOMPILER_STACK_FRAME_SCALE 2

1043-10441040int

10451041_PyAST_Validate(mod_tymod)

10461042{

@@ -1057,9 +1053,9 @@ _PyAST_Validate(mod_ty mod)

10571053 }

10581054/* Be careful here to prevent overflow. */

10591055intrecursion_depth=Py_C_RECURSION_LIMIT-tstate->c_recursion_remaining;

1060-starting_recursion_depth=recursion_depth*COMPILER_STACK_FRAME_SCALE;

1056+starting_recursion_depth=recursion_depth;

10611057state.recursion_depth=starting_recursion_depth;

1062-state.recursion_limit=Py_C_RECURSION_LIMIT*COMPILER_STACK_FRAME_SCALE;

1058+state.recursion_limit=Py_C_RECURSION_LIMIT;

1063105910641060switch (mod->kind) {

10651061caseModule_kind: