Skip to content

Commit a2c2a78

Browse files
committed
Check C stack depth before stack allocating JIT optimizer struct
1 parent af15e1d commit a2c2a78

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

Lib/test/test_call.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ def c_py_recurse(m):
10751075
c_py_recurse(100_000)
10761076

10771077

1078+
10781079
class TestFunctionWithManyArgs(unittest.TestCase):
10791080
def test_function_with_many_args(self):
10801081
for N in (10, 500, 1000):

Lib/test/test_capi/test_opt.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010

1111
from test.support import (script_helper, requires_specialization,
1212
import_helper, Py_GIL_DISABLED, requires_jit_enabled,
13-
reset_code)
13+
reset_code, infinite_recursion)
1414

1515
_testinternalcapi = import_helper.import_module("_testinternalcapi")
1616

1717
from _testinternalcapi import TIER2_THRESHOLD
18+
from _testcapi import pyobject_vectorcall
1819

1920

2021
@contextlib.contextmanager
@@ -2502,6 +2503,37 @@ def testfunc(n):
25022503
self.assertIn("_BINARY_OP", uops)
25032504

25042505

2506+
@requires_jit_enabled
2507+
class TestStackUse(unittest.TestCase):
2508+
2509+
def test_jit_at_depth(self):
2510+
2511+
def run_at_depth(n, func):
2512+
if n:
2513+
pyobject_vectorcall(run_at_depth, (n-1, func), None)
2514+
else:
2515+
func()
2516+
2517+
def find_stack_limit():
2518+
nonlocal depth
2519+
depth += 1
2520+
pyobject_vectorcall(find_stack_limit, (), None)
2521+
2522+
with infinite_recursion():
2523+
depth = 0
2524+
try:
2525+
find_stack_limit()
2526+
except RecursionError:
2527+
pass
2528+
2529+
def loop_func():
2530+
r = 0
2531+
for i in range(TIER2_THRESHOLD):
2532+
r += i
2533+
return r
2534+
run_at_depth(depth-1, loop_func)
2535+
2536+
25052537
def global_identity(x):
25062538
return x
25072539

Python/optimizer_analysis.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,11 @@ _Py_uop_analyze_and_optimize(
695695
)
696696
{
697697
OPT_STAT_INC(optimizer_attempts);
698+
/* Make sure we have enough C stack space for the optimizer */
699+
int margin = 1 + sizeof(JitOptContext)/_PyOS_STACK_MARGIN_BYTES;
700+
if (_Py_ReachedRecursionLimitWithMargin(_PyThreadState_GET(), margin)) {
701+
return 0;
702+
}
698703

699704
int err = remove_globals(frame, buffer, length, dependencies);
700705
if (err <= 0) {

0 commit comments

Comments
 (0)