mirror of
https://github.com/python/cpython.git
synced 2025-12-07 13:50:06 +00:00
GH-139914: Handle stack growth direction on HPPA (GH-140028)
Adapted from a patch for Python 3.14 submitted to the Debian BTS by John https://bugs.debian.org/1105111#20 Co-authored-by: John David Anglin <dave.anglin@bell.net>
This commit is contained in:
parent
336366fd7c
commit
f6dd9c12a8
10 changed files with 94 additions and 5 deletions
|
|
@ -217,7 +217,11 @@ extern void _PyEval_DeactivateOpCache(void);
|
||||||
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
|
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
|
||||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
return here_addr < _tstate->c_stack_soft_limit;
|
return here_addr < _tstate->c_stack_soft_limit;
|
||||||
|
#else
|
||||||
|
return here_addr > _tstate->c_stack_soft_limit;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export for '_json' shared extension, used via _Py_EnterRecursiveCall()
|
// Export for '_json' shared extension, used via _Py_EnterRecursiveCall()
|
||||||
|
|
@ -249,7 +253,11 @@ static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) {
|
||||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
assert(_tstate->c_stack_hard_limit != 0);
|
assert(_tstate->c_stack_hard_limit != 0);
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
return here_addr <= _tstate->c_stack_soft_limit;
|
return here_addr <= _tstate->c_stack_soft_limit;
|
||||||
|
#else
|
||||||
|
return here_addr >= _tstate->c_stack_soft_limit;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _Py_LeaveRecursiveCall(void) {
|
static inline void _Py_LeaveRecursiveCall(void) {
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,11 @@ _Py_RecursionLimit_GetMargin(PyThreadState *tstate)
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
assert(_tstate->c_stack_hard_limit != 0);
|
assert(_tstate->c_stack_hard_limit != 0);
|
||||||
intptr_t here_addr = _Py_get_machine_stack_pointer();
|
intptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, here_addr - (intptr_t)_tstate->c_stack_soft_limit, _PyOS_STACK_MARGIN_SHIFT);
|
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, here_addr - (intptr_t)_tstate->c_stack_soft_limit, _PyOS_STACK_MARGIN_SHIFT);
|
||||||
|
#else
|
||||||
|
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (intptr_t)_tstate->c_stack_soft_limit - here_addr, _PyOS_STACK_MARGIN_SHIFT);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -677,4 +677,10 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Assume the stack grows down unless specified otherwise
|
||||||
|
#ifndef _Py_STACK_GROWS_DOWN
|
||||||
|
# define _Py_STACK_GROWS_DOWN 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* Py_PYPORT_H */
|
#endif /* Py_PYPORT_H */
|
||||||
|
|
|
||||||
|
|
@ -1048,9 +1048,14 @@ def get_sp():
|
||||||
|
|
||||||
this_sp = _testinternalcapi.get_stack_pointer()
|
this_sp = _testinternalcapi.get_stack_pointer()
|
||||||
lower_sp = _testcapi.pyobject_vectorcall(get_sp, (), ())
|
lower_sp = _testcapi.pyobject_vectorcall(get_sp, (), ())
|
||||||
self.assertLess(lower_sp, this_sp)
|
if _testcapi._Py_STACK_GROWS_DOWN:
|
||||||
|
self.assertLess(lower_sp, this_sp)
|
||||||
|
safe_margin = this_sp - lower_sp
|
||||||
|
else:
|
||||||
|
self.assertGreater(lower_sp, this_sp)
|
||||||
|
safe_margin = lower_sp - this_sp
|
||||||
# Add an (arbitrary) extra 25% for safety
|
# Add an (arbitrary) extra 25% for safety
|
||||||
safe_margin = (this_sp - lower_sp) * 5 / 4
|
safe_margin = safe_margin * 5 / 4
|
||||||
self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())
|
self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())
|
||||||
|
|
||||||
@skip_on_s390x
|
@skip_on_s390x
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Restore support for HP PA-RISC, which has an upwards-growing stack.
|
||||||
|
|
@ -3359,6 +3359,10 @@ _testcapi_exec(PyObject *m)
|
||||||
PyModule_AddObject(m, "INT64_MAX", PyLong_FromInt64(INT64_MAX));
|
PyModule_AddObject(m, "INT64_MAX", PyLong_FromInt64(INT64_MAX));
|
||||||
PyModule_AddObject(m, "UINT64_MAX", PyLong_FromUInt64(UINT64_MAX));
|
PyModule_AddObject(m, "UINT64_MAX", PyLong_FromUInt64(UINT64_MAX));
|
||||||
|
|
||||||
|
if (PyModule_AddIntMacro(m, _Py_STACK_GROWS_DOWN)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (PyModule_AddIntMacro(m, Py_single_input)) {
|
if (PyModule_AddIntMacro(m, Py_single_input)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -351,13 +351,21 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count)
|
||||||
{
|
{
|
||||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
if (here_addr > _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES) {
|
if (here_addr > _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES) {
|
||||||
|
#else
|
||||||
|
if (here_addr <= _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES) {
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (_tstate->c_stack_hard_limit == 0) {
|
if (_tstate->c_stack_hard_limit == 0) {
|
||||||
_Py_InitializeRecursionLimits(tstate);
|
_Py_InitializeRecursionLimits(tstate);
|
||||||
}
|
}
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
return here_addr <= _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES;
|
return here_addr <= _tstate->c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES;
|
||||||
|
#else
|
||||||
|
return here_addr > _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -365,7 +373,11 @@ _Py_EnterRecursiveCallUnchecked(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
if (here_addr < _tstate->c_stack_hard_limit) {
|
if (here_addr < _tstate->c_stack_hard_limit) {
|
||||||
|
#else
|
||||||
|
if (here_addr > _tstate->c_stack_hard_limit) {
|
||||||
|
#endif
|
||||||
Py_FatalError("Unchecked stack overflow.");
|
Py_FatalError("Unchecked stack overflow.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -496,18 +508,33 @@ tstate_set_stack(PyThreadState *tstate,
|
||||||
#ifdef _Py_THREAD_SANITIZER
|
#ifdef _Py_THREAD_SANITIZER
|
||||||
// Thread sanitizer crashes if we use more than half the stack.
|
// Thread sanitizer crashes if we use more than half the stack.
|
||||||
uintptr_t stacksize = top - base;
|
uintptr_t stacksize = top - base;
|
||||||
base += stacksize / 2;
|
# if _Py_STACK_GROWS_DOWN
|
||||||
|
base += stacksize/2;
|
||||||
|
# else
|
||||||
|
top -= stacksize/2;
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
_tstate->c_stack_top = top;
|
_tstate->c_stack_top = top;
|
||||||
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
|
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
|
||||||
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
|
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
|
||||||
|
# ifndef NDEBUG
|
||||||
#ifndef NDEBUG
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
|
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
|
||||||
assert(ts->c_stack_hard_limit <= ts->c_stack_soft_limit);
|
assert(ts->c_stack_hard_limit <= ts->c_stack_soft_limit);
|
||||||
assert(ts->c_stack_soft_limit < ts->c_stack_top);
|
assert(ts->c_stack_soft_limit < ts->c_stack_top);
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
_tstate->c_stack_top = base;
|
||||||
|
_tstate->c_stack_hard_limit = top - _PyOS_STACK_MARGIN_BYTES;
|
||||||
|
_tstate->c_stack_soft_limit = top - _PyOS_STACK_MARGIN_BYTES * 2;
|
||||||
|
# ifndef NDEBUG
|
||||||
|
// Sanity checks
|
||||||
|
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
|
||||||
|
assert(ts->c_stack_hard_limit >= ts->c_stack_soft_limit);
|
||||||
|
assert(ts->c_stack_soft_limit > ts->c_stack_top);
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,9 +595,15 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
|
||||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||||
assert(_tstate->c_stack_soft_limit != 0);
|
assert(_tstate->c_stack_soft_limit != 0);
|
||||||
assert(_tstate->c_stack_hard_limit != 0);
|
assert(_tstate->c_stack_hard_limit != 0);
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
if (here_addr < _tstate->c_stack_hard_limit) {
|
if (here_addr < _tstate->c_stack_hard_limit) {
|
||||||
/* Overflowing while handling an overflow. Give up. */
|
/* Overflowing while handling an overflow. Give up. */
|
||||||
int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024;
|
int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024;
|
||||||
|
#else
|
||||||
|
if (here_addr > _tstate->c_stack_hard_limit) {
|
||||||
|
/* Overflowing while handling an overflow. Give up. */
|
||||||
|
int kbytes_used = (int)(here_addr - _tstate->c_stack_top)/1024;
|
||||||
|
#endif
|
||||||
char buffer[80];
|
char buffer[80];
|
||||||
snprintf(buffer, 80, "Unrecoverable stack overflow (used %d kB)%s", kbytes_used, where);
|
snprintf(buffer, 80, "Unrecoverable stack overflow (used %d kB)%s", kbytes_used, where);
|
||||||
Py_FatalError(buffer);
|
Py_FatalError(buffer);
|
||||||
|
|
@ -579,7 +612,11 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
#if _Py_STACK_GROWS_DOWN
|
||||||
int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024;
|
int kbytes_used = (int)(_tstate->c_stack_top - here_addr)/1024;
|
||||||
|
#else
|
||||||
|
int kbytes_used = (int)(here_addr - _tstate->c_stack_top)/1024;
|
||||||
|
#endif
|
||||||
tstate->recursion_headroom++;
|
tstate->recursion_headroom++;
|
||||||
_PyErr_Format(tstate, PyExc_RecursionError,
|
_PyErr_Format(tstate, PyExc_RecursionError,
|
||||||
"Stack overflow (used %d kB)%s",
|
"Stack overflow (used %d kB)%s",
|
||||||
|
|
|
||||||
13
configure
generated
vendored
13
configure
generated
vendored
|
|
@ -967,6 +967,7 @@ LDLIBRARY
|
||||||
LIBRARY
|
LIBRARY
|
||||||
BUILDEXEEXT
|
BUILDEXEEXT
|
||||||
NO_AS_NEEDED
|
NO_AS_NEEDED
|
||||||
|
_Py_STACK_GROWS_DOWN
|
||||||
MULTIARCH_CPPFLAGS
|
MULTIARCH_CPPFLAGS
|
||||||
PLATFORM_TRIPLET
|
PLATFORM_TRIPLET
|
||||||
MULTIARCH
|
MULTIARCH
|
||||||
|
|
@ -7213,6 +7214,18 @@ if test x$MULTIARCH != x; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Guess C stack direction
|
||||||
|
case $host in #(
|
||||||
|
hppa*) :
|
||||||
|
_Py_STACK_GROWS_DOWN=0 ;; #(
|
||||||
|
*) :
|
||||||
|
_Py_STACK_GROWS_DOWN=1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf "%s\n" "#define _Py_STACK_GROWS_DOWN $_Py_STACK_GROWS_DOWN" >>confdefs.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PEP 11 support tier" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PEP 11 support tier" >&5
|
||||||
printf %s "checking for PEP 11 support tier... " >&6; }
|
printf %s "checking for PEP 11 support tier... " >&6; }
|
||||||
case $host/$ac_cv_cc_name in #(
|
case $host/$ac_cv_cc_name in #(
|
||||||
|
|
|
||||||
|
|
@ -1202,6 +1202,14 @@ if test x$MULTIARCH != x; then
|
||||||
fi
|
fi
|
||||||
AC_SUBST([MULTIARCH_CPPFLAGS])
|
AC_SUBST([MULTIARCH_CPPFLAGS])
|
||||||
|
|
||||||
|
# Guess C stack direction
|
||||||
|
AS_CASE([$host],
|
||||||
|
[hppa*], [_Py_STACK_GROWS_DOWN=0],
|
||||||
|
[_Py_STACK_GROWS_DOWN=1])
|
||||||
|
AC_DEFINE_UNQUOTED([_Py_STACK_GROWS_DOWN], [$_Py_STACK_GROWS_DOWN],
|
||||||
|
[Define to 1 if the machine stack grows down (default); 0 if it grows up.])
|
||||||
|
AC_SUBST([_Py_STACK_GROWS_DOWN])
|
||||||
|
|
||||||
dnl Support tiers according to https://peps.python.org/pep-0011/
|
dnl Support tiers according to https://peps.python.org/pep-0011/
|
||||||
dnl
|
dnl
|
||||||
dnl NOTE: Windows support tiers are defined in PC/pyconfig.h.
|
dnl NOTE: Windows support tiers are defined in PC/pyconfig.h.
|
||||||
|
|
|
||||||
|
|
@ -2050,6 +2050,9 @@
|
||||||
/* HACL* library can compile SIMD256 implementations */
|
/* HACL* library can compile SIMD256 implementations */
|
||||||
#undef _Py_HACL_CAN_COMPILE_VEC256
|
#undef _Py_HACL_CAN_COMPILE_VEC256
|
||||||
|
|
||||||
|
/* Define to 1 if the machine stack grows down (default); 0 if it grows up. */
|
||||||
|
#undef _Py_STACK_GROWS_DOWN
|
||||||
|
|
||||||
/* Define if you want to use tail-calling interpreters in CPython. */
|
/* Define if you want to use tail-calling interpreters in CPython. */
|
||||||
#undef _Py_TAIL_CALL_INTERP
|
#undef _Py_TAIL_CALL_INTERP
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue