Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bd89bca

Browse filesBrowse files
authored
gh-111798: Use lower Py_C_RECURSION_LIMIT in debug mode (#112124)
* Run again test_ast_recursion_limit() on WASI platform. * Add _testinternalcapi.get_c_recursion_remaining(). * Fix test_ast and test_sys_settrace: test_ast_recursion_limit() and test_trace_unpack_long_sequence() now adjust the maximum recursion depth depending on the the remaining C recursion.
1 parent 81ab0e8 commit bd89bca
Copy full SHA for bd89bca

File tree

Expand file treeCollapse file tree

5 files changed

+37
-5
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+37
-5
lines changed

‎Include/cpython/pystate.h

Copy file name to clipboardExpand all lines: Include/cpython/pystate.h
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ struct _ts {
214214

215215
};
216216

217-
#ifdef __wasi__
217+
#ifdef Py_DEBUG
218+
// A debug build is likely built with low optimization level which implies
219+
// higher stack memory usage than a release build: use a lower limit.
220+
# define Py_C_RECURSION_LIMIT 500
221+
#elif defined(__wasi__)
218222
// WASI has limited call stack. Python's recursion limit depends on code
219223
// layout, optimization, and WASI runtime. Wasmtime can handle about 700
220224
// recursions, sometimes less. 500 is a more conservative limit.

‎Lib/test/test_ast.py

Copy file name to clipboardExpand all lines: Lib/test/test_ast.py
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
import weakref
1313
from functools import partial
1414
from textwrap import dedent
15+
try:
16+
import _testinternalcapi
17+
except ImportError:
18+
_testinternalcapi = None
1519

1620
from test import support
1721
from test.support.import_helper import import_fresh_module
@@ -1118,12 +1122,14 @@ def next(self):
11181122
return self
11191123
enum._test_simple_enum(_Precedence, ast._Precedence)
11201124

1121-
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
11221125
@support.cpython_only
11231126
def test_ast_recursion_limit(self):
11241127
fail_depth = support.EXCEEDS_RECURSION_LIMIT
11251128
crash_depth = 100_000
11261129
success_depth = 1200
1130+
if _testinternalcapi is not None:
1131+
remaining = _testinternalcapi.get_c_recursion_remaining()
1132+
success_depth = min(success_depth, remaining)
11271133

11281134
def check_limit(prefix, repeated):
11291135
expect_ok = prefix + repeated * success_depth

‎Lib/test/test_sys_settrace.py

Copy file name to clipboardExpand all lines: Lib/test/test_sys_settrace.py
+12-3Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
import textwrap
1515
import subprocess
1616
import warnings
17+
try:
18+
import _testinternalcapi
19+
except ImportError:
20+
_testinternalcapi = None
1721

1822
support.requires_working_socket(module=True)
1923

@@ -3033,16 +3037,21 @@ def test_trace_unpack_long_sequence(self):
30333037
self.assertEqual(counts, {'call': 1, 'line': 301, 'return': 1})
30343038

30353039
def test_trace_lots_of_globals(self):
3040+
count = 1000
3041+
if _testinternalcapi is not None:
3042+
remaining = _testinternalcapi.get_c_recursion_remaining()
3043+
count = min(count, remaining)
3044+
30363045
code = """if 1:
30373046
def f():
30383047
return (
30393048
{}
30403049
)
3041-
""".format("\n+\n".join(f"var{i}\n" for i in range(1000)))
3042-
ns = {f"var{i}": i for i in range(1000)}
3050+
""".format("\n+\n".join(f"var{i}\n" for i in range(count)))
3051+
ns = {f"var{i}": i for i in range(count)}
30433052
exec(code, ns)
30443053
counts = self.count_traces(ns["f"])
3045-
self.assertEqual(counts, {'call': 1, 'line': 2000, 'return': 1})
3054+
self.assertEqual(counts, {'call': 1, 'line': count * 2, 'return': 1})
30463055

30473056

30483057
class TestEdgeCases(unittest.TestCase):
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
When Python is built in debug mode, set the C recursion limit to 500 instead
2+
of 1500. A debug build is likely built with low optimization level which
3+
implies higher stack memory usage than a release build. Patch by Victor
4+
Stinner.

‎Modules/_testinternalcapi.c

Copy file name to clipboardExpand all lines: Modules/_testinternalcapi.c
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
109109
}
110110

111111

112+
static PyObject*
113+
get_c_recursion_remaining(PyObject *self, PyObject *Py_UNUSED(args))
114+
{
115+
PyThreadState *tstate = _PyThreadState_GET();
116+
return PyLong_FromLong(tstate->c_recursion_remaining);
117+
}
118+
119+
112120
static PyObject*
113121
test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
114122
{
@@ -1611,6 +1619,7 @@ perf_trampoline_set_persist_after_fork(PyObject *self, PyObject *args)
16111619
static PyMethodDef module_functions[] = {
16121620
{"get_configs", get_configs, METH_NOARGS},
16131621
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
1622+
{"get_c_recursion_remaining", get_c_recursion_remaining, METH_NOARGS},
16141623
{"test_bswap", test_bswap, METH_NOARGS},
16151624
{"test_popcount", test_popcount, METH_NOARGS},
16161625
{"test_bit_length", test_bit_length, METH_NOARGS},

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.