Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,7 @@ def c_py_recurse(m):
c_py_recurse(100_000)



class TestFunctionWithManyArgs(unittest.TestCase):
def test_function_with_many_args(self):
for N in (10, 500, 1000):
Expand Down
34 changes: 33 additions & 1 deletion Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@

from test.support import (script_helper, requires_specialization,
import_helper, Py_GIL_DISABLED, requires_jit_enabled,
reset_code)
reset_code, infinite_recursion)

_testinternalcapi = import_helper.import_module("_testinternalcapi")

from _testinternalcapi import TIER2_THRESHOLD
from _testcapi import pyobject_vectorcall


@contextlib.contextmanager
Expand Down Expand Up @@ -2502,6 +2503,37 @@ def testfunc(n):
self.assertIn("_BINARY_OP", uops)


@requires_jit_enabled
class TestStackUse(unittest.TestCase):

def test_jit_at_depth(self):

def run_at_depth(n, func):
if n:
pyobject_vectorcall(run_at_depth, (n-1, func), None)
else:
func()

def find_stack_limit():
nonlocal depth
depth += 1
pyobject_vectorcall(find_stack_limit, (), None)

with infinite_recursion():
depth = 0
try:
find_stack_limit()
except RecursionError:
pass

def loop_func():
r = 0
for i in range(TIER2_THRESHOLD):
r += i
return r
run_at_depth(depth-1, loop_func)


def global_identity(x):
return x

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Guard against C stack overflow when JIT compiling.
5 changes: 5 additions & 0 deletions Python/optimizer_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,11 @@ _Py_uop_analyze_and_optimize(
)
{
OPT_STAT_INC(optimizer_attempts);
/* Make sure we have enough C stack space for the optimizer */
int margin = 1 + sizeof(JitOptContext)/_PyOS_STACK_MARGIN_BYTES;
if (_Py_ReachedRecursionLimitWithMargin(_PyThreadState_GET(), margin)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To work properly, the optimize_uops function or this function must be marked Py_NO_INLINE as well.

Otherwise, the compiler can just inline the functions and hoist the alloca above the check, making the check useless.

return 0;
}

int err = remove_globals(frame, buffer, length, dependencies);
if (err <= 0) {
Expand Down
Loading