Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Copy link
Member

Choose a reason for hiding this comment

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

Is ‘guess’ the right word here?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. For an arbitrary platform we can't really be sure.

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