Skip to content

Commit 8de23c0

Browse files
committed
Fix C stack limits by factoring out finding hardware stack limits
1 parent 7016044 commit 8de23c0

File tree

1 file changed

+32
-28
lines changed

1 file changed

+32
-28
lines changed

Python/ceval.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -438,31 +438,26 @@ int pthread_attr_destroy(pthread_attr_t *a)
438438

439439
#endif
440440

441-
442-
void
443-
_Py_InitializeRecursionLimits(PyThreadState *tstate)
441+
static void
442+
hardware_stack_limits(uintptr_t *top, uintptr_t *base)
444443
{
445-
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
446444
#ifdef WIN32
447445
ULONG_PTR low, high;
448446
GetCurrentThreadStackLimits(&low, &high);
449-
_tstate->c_stack_top = (uintptr_t)high;
447+
*top = (uintptr_t)high;
450448
ULONG guarantee = 0;
451449
SetThreadStackGuarantee(&guarantee);
452-
_tstate->c_stack_hard_limit = ((uintptr_t)low) + guarantee + _PyOS_STACK_MARGIN_BYTES;
453-
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
450+
*base = (uintptr_t)low + guarantee;
454451
#elif defined(__APPLE__)
455452
pthread_t this_thread = pthread_self();
456453
void *stack_addr = pthread_get_stackaddr_np(this_thread); // top of the stack
457454
size_t stack_size = pthread_get_stacksize_np(this_thread);
458-
_tstate->c_stack_top = (uintptr_t)stack_addr;
459-
_tstate->c_stack_hard_limit = _tstate->c_stack_top - stack_size;
460-
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
455+
*top = (uintptr_t)stack_addr;
456+
*base = ((uintptr_t)stack_addr) - stack_size;
461457
#else
462-
uintptr_t here_addr = _Py_get_machine_stack_pointer();
463-
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
464-
/// (on alpine at least) is much smaller than expected and imposes undue limits
465-
/// compared to the old stack size estimation. (We assume musl is not glibc.)
458+
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
459+
/// (on alpine at least) is much smaller than expected and imposes undue limits
460+
/// compared to the old stack size estimation. (We assume musl is not glibc.)
466461
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
467462
!defined(__NetBSD__) && (defined(__GLIBC__) || !defined(__linux__))
468463
size_t stack_size, guard_size;
@@ -475,26 +470,35 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
475470
err |= pthread_attr_destroy(&attr);
476471
}
477472
if (err == 0) {
478-
uintptr_t base = ((uintptr_t)stack_addr) + guard_size;
479-
_tstate->c_stack_top = base + stack_size;
480-
#ifdef _Py_THREAD_SANITIZER
481-
// Thread sanitizer crashes if we use a bit more than half the stack.
482-
_tstate->c_stack_soft_limit = base + (stack_size / 2);
483-
#else
484-
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
485-
#endif
486-
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
487-
assert(_tstate->c_stack_soft_limit < here_addr);
488-
assert(here_addr < _tstate->c_stack_top);
473+
*base = ((uintptr_t)stack_addr) + guard_size;
474+
*top = (uintptr_t)stack_addr + stack_size;
489475
return;
490476
}
491477
# endif
492-
_tstate->c_stack_top = _Py_SIZE_ROUND_UP(here_addr, 4096);
493-
_tstate->c_stack_soft_limit = _tstate->c_stack_top - Py_C_STACK_SIZE;
494-
_tstate->c_stack_hard_limit = _tstate->c_stack_top - (Py_C_STACK_SIZE + _PyOS_STACK_MARGIN_BYTES);
478+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
479+
uintptr_t top_addr = _Py_SIZE_ROUND_UP(here_addr, 4096);
480+
*top = top_addr;
481+
*base = top_addr - Py_C_STACK_SIZE;
495482
#endif
496483
}
497484

485+
void
486+
_Py_InitializeRecursionLimits(PyThreadState *tstate)
487+
{
488+
uintptr_t top;
489+
uintptr_t base;
490+
hardware_stack_limits(&top, &base);
491+
#ifdef _Py_THREAD_SANITIZER
492+
// Thread sanitizer crashes if we use more than half the stack.
493+
uintptr_t stacksize = top - base;
494+
base += stacksize/2;
495+
#endif
496+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
497+
_tstate->c_stack_top = top;
498+
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
499+
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
500+
}
501+
498502
/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
499503
if the recursion_depth reaches recursion_limit. */
500504
int

0 commit comments

Comments
 (0)