mirror of https://github.com/python/cpython
GH-91079: Rename C_RECURSION_LIMIT to Py_C_RECURSION_LIMIT (#108507)
Symbols of the C API should be prefixed by "Py_" to avoid conflict with existing names in 3rd party C extensions on "#include <Python.h>". test.pythoninfo now logs Py_C_RECURSION_LIMIT constant and other _testcapi and _testinternalcapi constants.
This commit is contained in:
parent
15d4c9fabc
commit
b0edf3b98e
|
@ -194,18 +194,17 @@ struct _ts {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* WASI has limited call stack. Python's recursion limit depends on code
|
|
||||||
layout, optimization, and WASI runtime. Wasmtime can handle about 700
|
|
||||||
recursions, sometimes less. 500 is a more conservative limit. */
|
|
||||||
#ifndef C_RECURSION_LIMIT
|
|
||||||
#ifdef __wasi__
|
#ifdef __wasi__
|
||||||
# define C_RECURSION_LIMIT 500
|
// WASI has limited call stack. Python's recursion limit depends on code
|
||||||
|
// layout, optimization, and WASI runtime. Wasmtime can handle about 700
|
||||||
|
// recursions, sometimes less. 500 is a more conservative limit.
|
||||||
|
# define Py_C_RECURSION_LIMIT 500
|
||||||
#else
|
#else
|
||||||
// This value is duplicated in Lib/test/support/__init__.py
|
// This value is duplicated in Lib/test/support/__init__.py
|
||||||
# define C_RECURSION_LIMIT 1500
|
# define Py_C_RECURSION_LIMIT 1500
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* other API */
|
/* other API */
|
||||||
|
|
||||||
/* Similar to PyThreadState_Get(), but don't issue a fatal error
|
/* Similar to PyThreadState_Get(), but don't issue a fatal error
|
||||||
|
|
|
@ -6,7 +6,7 @@ import sys
|
||||||
from functools import cmp_to_key
|
from functools import cmp_to_key
|
||||||
|
|
||||||
from test import seq_tests
|
from test import seq_tests
|
||||||
from test.support import ALWAYS_EQ, NEVER_EQ, C_RECURSION_LIMIT
|
from test.support import ALWAYS_EQ, NEVER_EQ, Py_C_RECURSION_LIMIT
|
||||||
|
|
||||||
|
|
||||||
class CommonTest(seq_tests.CommonTest):
|
class CommonTest(seq_tests.CommonTest):
|
||||||
|
@ -61,7 +61,7 @@ class CommonTest(seq_tests.CommonTest):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
a = self.type2test([])
|
a = self.type2test([])
|
||||||
for i in range(C_RECURSION_LIMIT + 1):
|
for i in range(Py_C_RECURSION_LIMIT + 1):
|
||||||
a = self.type2test([a])
|
a = self.type2test([a])
|
||||||
self.assertRaises(RecursionError, repr, a)
|
self.assertRaises(RecursionError, repr, a)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
import collections
|
import collections
|
||||||
import sys
|
import sys
|
||||||
from test.support import C_RECURSION_LIMIT
|
from test.support import Py_C_RECURSION_LIMIT
|
||||||
|
|
||||||
|
|
||||||
class BasicTestMappingProtocol(unittest.TestCase):
|
class BasicTestMappingProtocol(unittest.TestCase):
|
||||||
|
@ -625,7 +625,7 @@ class TestHashMappingProtocol(TestMappingProtocol):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
d = self._empty_mapping()
|
d = self._empty_mapping()
|
||||||
for i in range(C_RECURSION_LIMIT + 1):
|
for i in range(Py_C_RECURSION_LIMIT + 1):
|
||||||
d0 = d
|
d0 = d
|
||||||
d = self._empty_mapping()
|
d = self._empty_mapping()
|
||||||
d[1] = d0
|
d[1] = d0
|
||||||
|
|
|
@ -665,6 +665,22 @@ def collect_decimal(info_add):
|
||||||
|
|
||||||
|
|
||||||
def collect_testcapi(info_add):
|
def collect_testcapi(info_add):
|
||||||
|
try:
|
||||||
|
import _testcapi
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
|
||||||
|
for name in (
|
||||||
|
'LONG_MAX', # always 32-bit on Windows, 64-bit on 64-bit Unix
|
||||||
|
'PY_SSIZE_T_MAX',
|
||||||
|
'Py_C_RECURSION_LIMIT',
|
||||||
|
'SIZEOF_TIME_T', # 32-bit or 64-bit depending on the platform
|
||||||
|
'SIZEOF_WCHAR_T', # 16-bit or 32-bit depending on the platform
|
||||||
|
):
|
||||||
|
copy_attr(info_add, f'_testcapi.{name}', _testcapi, name)
|
||||||
|
|
||||||
|
|
||||||
|
def collect_testinternalcapi(info_add):
|
||||||
try:
|
try:
|
||||||
import _testinternalcapi
|
import _testinternalcapi
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -672,6 +688,12 @@ def collect_testcapi(info_add):
|
||||||
|
|
||||||
call_func(info_add, 'pymem.allocator', _testinternalcapi, 'pymem_getallocatorsname')
|
call_func(info_add, 'pymem.allocator', _testinternalcapi, 'pymem_getallocatorsname')
|
||||||
|
|
||||||
|
for name in (
|
||||||
|
'SIZEOF_PYGC_HEAD',
|
||||||
|
'SIZEOF_PYOBJECT',
|
||||||
|
):
|
||||||
|
copy_attr(info_add, f'_testinternalcapi.{name}', _testinternalcapi, name)
|
||||||
|
|
||||||
|
|
||||||
def collect_resource(info_add):
|
def collect_resource(info_add):
|
||||||
try:
|
try:
|
||||||
|
@ -907,6 +929,7 @@ def collect_info(info):
|
||||||
collect_sys,
|
collect_sys,
|
||||||
collect_sysconfig,
|
collect_sysconfig,
|
||||||
collect_testcapi,
|
collect_testcapi,
|
||||||
|
collect_testinternalcapi,
|
||||||
collect_time,
|
collect_time,
|
||||||
collect_tkinter,
|
collect_tkinter,
|
||||||
collect_windows,
|
collect_windows,
|
||||||
|
|
|
@ -60,7 +60,7 @@ __all__ = [
|
||||||
"run_with_tz", "PGO", "missing_compiler_executable",
|
"run_with_tz", "PGO", "missing_compiler_executable",
|
||||||
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
|
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
|
||||||
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
|
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
|
||||||
"Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "C_RECURSION_LIMIT",
|
"Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "Py_C_RECURSION_LIMIT",
|
||||||
"skip_on_s390x",
|
"skip_on_s390x",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2531,7 +2531,7 @@ def adjust_int_max_str_digits(max_digits):
|
||||||
EXCEEDS_RECURSION_LIMIT = 5000
|
EXCEEDS_RECURSION_LIMIT = 5000
|
||||||
|
|
||||||
# The default C recursion limit (from Include/cpython/pystate.h).
|
# The default C recursion limit (from Include/cpython/pystate.h).
|
||||||
C_RECURSION_LIMIT = 1500
|
Py_C_RECURSION_LIMIT = 1500
|
||||||
|
|
||||||
#Windows doesn't have os.uname() but it doesn't support s390x.
|
#Windows doesn't have os.uname() but it doesn't support s390x.
|
||||||
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
|
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
|
||||||
|
|
|
@ -11,7 +11,7 @@ import textwrap
|
||||||
import warnings
|
import warnings
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import (script_helper, requires_debug_ranges,
|
from test.support import (script_helper, requires_debug_ranges,
|
||||||
requires_specialization, C_RECURSION_LIMIT)
|
requires_specialization, Py_C_RECURSION_LIMIT)
|
||||||
from test.support.os_helper import FakePath
|
from test.support.os_helper import FakePath
|
||||||
|
|
||||||
class TestSpecifics(unittest.TestCase):
|
class TestSpecifics(unittest.TestCase):
|
||||||
|
@ -111,7 +111,7 @@ class TestSpecifics(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
||||||
def test_extended_arg(self):
|
def test_extended_arg(self):
|
||||||
repeat = int(C_RECURSION_LIMIT * 0.9)
|
repeat = int(Py_C_RECURSION_LIMIT * 0.9)
|
||||||
longexpr = 'x = x or ' + '-x' * repeat
|
longexpr = 'x = x or ' + '-x' * repeat
|
||||||
g = {}
|
g = {}
|
||||||
code = textwrap.dedent('''
|
code = textwrap.dedent('''
|
||||||
|
@ -557,12 +557,12 @@ class TestSpecifics(unittest.TestCase):
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
||||||
def test_compiler_recursion_limit(self):
|
def test_compiler_recursion_limit(self):
|
||||||
# Expected limit is C_RECURSION_LIMIT * 2
|
# Expected limit is Py_C_RECURSION_LIMIT * 2
|
||||||
# Duplicating the limit here is a little ugly.
|
# Duplicating the limit here is a little ugly.
|
||||||
# Perhaps it should be exposed somewhere...
|
# Perhaps it should be exposed somewhere...
|
||||||
fail_depth = C_RECURSION_LIMIT * 2 + 1
|
fail_depth = Py_C_RECURSION_LIMIT * 2 + 1
|
||||||
crash_depth = C_RECURSION_LIMIT * 100
|
crash_depth = Py_C_RECURSION_LIMIT * 100
|
||||||
success_depth = int(C_RECURSION_LIMIT * 1.8)
|
success_depth = int(Py_C_RECURSION_LIMIT * 1.8)
|
||||||
|
|
||||||
def check_limit(prefix, repeated, mode="single"):
|
def check_limit(prefix, repeated, mode="single"):
|
||||||
expect_ok = prefix + repeated * success_depth
|
expect_ok = prefix + repeated * success_depth
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
import unittest
|
import unittest
|
||||||
import weakref
|
import weakref
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import import_helper, C_RECURSION_LIMIT
|
from test.support import import_helper, Py_C_RECURSION_LIMIT
|
||||||
|
|
||||||
|
|
||||||
class DictTest(unittest.TestCase):
|
class DictTest(unittest.TestCase):
|
||||||
|
@ -596,7 +596,7 @@ class DictTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
d = {}
|
d = {}
|
||||||
for i in range(C_RECURSION_LIMIT + 1):
|
for i in range(Py_C_RECURSION_LIMIT + 1):
|
||||||
d = {1: d}
|
d = {1: d}
|
||||||
self.assertRaises(RecursionError, repr, d)
|
self.assertRaises(RecursionError, repr, d)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import copy
|
||||||
import pickle
|
import pickle
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import C_RECURSION_LIMIT
|
from test.support import Py_C_RECURSION_LIMIT
|
||||||
|
|
||||||
class DictSetTest(unittest.TestCase):
|
class DictSetTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ class DictSetTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_deeply_nested_repr(self):
|
def test_deeply_nested_repr(self):
|
||||||
d = {}
|
d = {}
|
||||||
for i in range(C_RECURSION_LIMIT//2 + 100):
|
for i in range(Py_C_RECURSION_LIMIT//2 + 100):
|
||||||
d = {42: d.values()}
|
d = {42: d.values()}
|
||||||
self.assertRaises(RecursionError, repr, d)
|
self.assertRaises(RecursionError, repr, d)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import collections.abc
|
import collections.abc
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import C_RECURSION_LIMIT
|
from test.support import Py_C_RECURSION_LIMIT
|
||||||
|
|
||||||
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
||||||
def test_exception_group_types(self):
|
def test_exception_group_types(self):
|
||||||
|
@ -460,7 +460,7 @@ class ExceptionGroupSplitTests(ExceptionGroupTestBase):
|
||||||
class DeepRecursionInSplitAndSubgroup(unittest.TestCase):
|
class DeepRecursionInSplitAndSubgroup(unittest.TestCase):
|
||||||
def make_deep_eg(self):
|
def make_deep_eg(self):
|
||||||
e = TypeError(1)
|
e = TypeError(1)
|
||||||
for i in range(C_RECURSION_LIMIT + 1):
|
for i in range(Py_C_RECURSION_LIMIT + 1):
|
||||||
e = ExceptionGroup('eg', [e])
|
e = ExceptionGroup('eg', [e])
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
|
|
@ -3922,6 +3922,7 @@ PyInit__testcapi(void)
|
||||||
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
|
PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type);
|
||||||
|
|
||||||
PyModule_AddIntConstant(m, "the_number_three", 3);
|
PyModule_AddIntConstant(m, "the_number_three", 3);
|
||||||
|
PyModule_AddIntMacro(m, Py_C_RECURSION_LIMIT);
|
||||||
|
|
||||||
TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
|
TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
|
||||||
Py_INCREF(TestError);
|
Py_INCREF(TestError);
|
||||||
|
|
|
@ -1552,6 +1552,11 @@ module_exec(PyObject *module)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PyModule_Add(module, "SIZEOF_PYOBJECT",
|
||||||
|
PyLong_FromSsize_t(sizeof(PyObject))) < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (PyModule_Add(module, "SIZEOF_TIME_T",
|
if (PyModule_Add(module, "SIZEOF_TIME_T",
|
||||||
PyLong_FromSsize_t(sizeof(time_t))) < 0) {
|
PyLong_FromSsize_t(sizeof(time_t))) < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1401,8 +1401,8 @@ PyObject* PyAST_mod2obj(mod_ty t)
|
||||||
if (!tstate) {
|
if (!tstate) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
state->recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
||||||
int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
||||||
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
||||||
state->recursion_depth = starting_recursion_depth;
|
state->recursion_depth = starting_recursion_depth;
|
||||||
|
|
||||||
|
|
|
@ -13081,8 +13081,8 @@ PyObject* PyAST_mod2obj(mod_ty t)
|
||||||
if (!tstate) {
|
if (!tstate) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
state->recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
||||||
int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
||||||
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
||||||
state->recursion_depth = starting_recursion_depth;
|
state->recursion_depth = starting_recursion_depth;
|
||||||
|
|
||||||
|
|
|
@ -1046,10 +1046,10 @@ _PyAST_Validate(mod_ty mod)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Be careful here to prevent overflow. */
|
/* Be careful here to prevent overflow. */
|
||||||
int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
||||||
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
||||||
state.recursion_depth = starting_recursion_depth;
|
state.recursion_depth = starting_recursion_depth;
|
||||||
state.recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
state.recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
||||||
|
|
||||||
switch (mod->kind) {
|
switch (mod->kind) {
|
||||||
case Module_kind:
|
case Module_kind:
|
||||||
|
|
|
@ -1130,10 +1130,10 @@ _PyAST_Optimize(mod_ty mod, PyArena *arena, int optimize, int ff_features)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Be careful here to prevent overflow. */
|
/* Be careful here to prevent overflow. */
|
||||||
int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
||||||
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
||||||
state.recursion_depth = starting_recursion_depth;
|
state.recursion_depth = starting_recursion_depth;
|
||||||
state.recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
state.recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
||||||
|
|
||||||
int ret = astfold_mod(mod, arena, &state);
|
int ret = astfold_mod(mod, arena, &state);
|
||||||
assert(ret || PyErr_Occurred());
|
assert(ret || PyErr_Occurred());
|
||||||
|
|
|
@ -1334,7 +1334,7 @@ init_threadstate(PyThreadState *tstate,
|
||||||
|
|
||||||
tstate->py_recursion_limit = interp->ceval.recursion_limit,
|
tstate->py_recursion_limit = interp->ceval.recursion_limit,
|
||||||
tstate->py_recursion_remaining = interp->ceval.recursion_limit,
|
tstate->py_recursion_remaining = interp->ceval.recursion_limit,
|
||||||
tstate->c_recursion_remaining = C_RECURSION_LIMIT;
|
tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT;
|
||||||
|
|
||||||
tstate->exc_info = &tstate->exc_state;
|
tstate->exc_info = &tstate->exc_state;
|
||||||
|
|
||||||
|
|
|
@ -312,10 +312,10 @@ _PySymtable_Build(mod_ty mod, PyObject *filename, PyFutureFeatures *future)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Be careful here to prevent overflow. */
|
/* Be careful here to prevent overflow. */
|
||||||
int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
int recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
|
||||||
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE;
|
||||||
st->recursion_depth = starting_recursion_depth;
|
st->recursion_depth = starting_recursion_depth;
|
||||||
st->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
st->recursion_limit = Py_C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE;
|
||||||
|
|
||||||
/* Make the initial symbol information gathering pass */
|
/* Make the initial symbol information gathering pass */
|
||||||
if (!symtable_enter_block(st, &_Py_ID(top), ModuleBlock, (void *)mod, 0, 0, 0, 0)) {
|
if (!symtable_enter_block(st, &_Py_ID(top), ModuleBlock, (void *)mod, 0, 0, 0, 0)) {
|
||||||
|
|
Loading…
Reference in New Issue