Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
8 changes: 8 additions & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,11 @@ extern void _PyEval_DeactivateOpCache(void);
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#if _Py_STACK_GROWS_DOWN
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()
Expand Down Expand Up @@ -249,7 +253,11 @@ static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) {
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
assert(_tstate->c_stack_hard_limit != 0);
#if _Py_STACK_GROWS_DOWN
return here_addr <= _tstate->c_stack_soft_limit;
#else
return here_addr >= _tstate->c_stack_soft_limit;
#endif
}

static inline void _Py_LeaveRecursiveCall(void) {
Expand Down
4 changes: 4 additions & 0 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,11 @@ _Py_RecursionLimit_GetMargin(PyThreadState *tstate)
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
assert(_tstate->c_stack_hard_limit != 0);
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);
#else
return Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, (intptr_t)_tstate->c_stack_soft_limit - here_addr, _PyOS_STACK_MARGIN_SHIFT);
#endif
}

#ifdef __cplusplus
Expand Down
6 changes: 6 additions & 0 deletions Include/pyport.h
Original file line number Diff line number Diff line change
Expand Up @@ -682,4 +682,10 @@ extern "C" {
#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 */
7 changes: 5 additions & 2 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -1048,9 +1048,12 @@ def get_sp():

this_sp = _testinternalcapi.get_stack_pointer()
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)
else:
self.assertGreater(lower_sp, this_sp)
# Add an (arbitrary) extra 25% for safety
safe_margin = (this_sp - lower_sp) * 5 / 4
safe_margin = abs(this_sp - lower_sp) * 5 / 4
self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())

@skip_on_s390x
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restore support for HP PA-RISC, which has an upwards-growing stack.
4 changes: 4 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3324,6 +3324,10 @@ _testcapi_exec(PyObject *m)
PyModule_AddObject(m, "INT64_MAX", PyLong_FromInt64(INT64_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)) {
return -1;
}
Expand Down
32 changes: 32 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,21 +347,33 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count)
{
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#if _Py_STACK_GROWS_DOWN
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;
}
if (_tstate->c_stack_hard_limit == 0) {
_Py_InitializeRecursionLimits(tstate);
}
#if _Py_STACK_GROWS_DOWN
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
_Py_EnterRecursiveCallUnchecked(PyThreadState *tstate)
{
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#if _Py_STACK_GROWS_DOWN
if (here_addr < _tstate->c_stack_hard_limit) {
#else
if (here_addr > _tstate->c_stack_hard_limit) {
#endif
Py_FatalError("Unchecked stack overflow.");
}
}
Expand Down Expand Up @@ -491,12 +503,22 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
#ifdef _Py_THREAD_SANITIZER
// Thread sanitizer crashes if we use more than half the stack.
uintptr_t stacksize = top - base;
# if _Py_STACK_GROWS_DOWN
base += stacksize/2;
# else
top -= stacksize/2;
# endif
#endif
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#if _Py_STACK_GROWS_DOWN
_tstate->c_stack_top = top;
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
#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;
#endif
}

/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
Expand All @@ -508,9 +530,15 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
uintptr_t here_addr = _Py_get_machine_stack_pointer();
assert(_tstate->c_stack_soft_limit != 0);
assert(_tstate->c_stack_hard_limit != 0);
#if _Py_STACK_GROWS_DOWN
if (here_addr < _tstate->c_stack_hard_limit) {
/* Overflowing while handling an overflow. Give up. */
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];
snprintf(buffer, 80, "Unrecoverable stack overflow (used %d kB)%s", kbytes_used, where);
Py_FatalError(buffer);
Expand All @@ -519,7 +547,11 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
return 0;
}
else {
#if _Py_STACK_GROWS_DOWN
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++;
_PyErr_Format(tstate, PyExc_RecursionError,
"Stack overflow (used %d kB)%s",
Expand Down
13 changes: 13 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,14 @@ if test x$MULTIARCH != x; then
fi
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
dnl NOTE: Windows support tiers are defined in PC/pyconfig.h.
Expand Down
3 changes: 3 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -2026,6 +2026,9 @@
/* HACL* library can compile SIMD256 implementations */
#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. */
#undef _Py_TAIL_CALL_INTERP

Expand Down
Loading