Skip to content

Commit 0300367

Browse files
markshannonencukou
authored andcommitted
pythonGH-139291: Fix C stack limits by factoring out finding hardware stack limits (pythonGH-139294)
1 parent 7752629 commit 0300367

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
@@ -424,31 +424,26 @@ int pthread_attr_destroy(pthread_attr_t *a)
424424

425425
#endif
426426

427-
428-
void
429-
_Py_InitializeRecursionLimits(PyThreadState *tstate)
427+
static void
428+
hardware_stack_limits(uintptr_t *top, uintptr_t *base)
430429
{
431-
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
432430
#ifdef WIN32
433431
ULONG_PTR low, high;
434432
GetCurrentThreadStackLimits(&low, &high);
435-
_tstate->c_stack_top = (uintptr_t)high;
433+
*top = (uintptr_t)high;
436434
ULONG guarantee = 0;
437435
SetThreadStackGuarantee(&guarantee);
438-
_tstate->c_stack_hard_limit = ((uintptr_t)low) + guarantee + _PyOS_STACK_MARGIN_BYTES;
439-
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
436+
*base = (uintptr_t)low + guarantee;
440437
#elif defined(__APPLE__)
441438
pthread_t this_thread = pthread_self();
442439
void *stack_addr = pthread_get_stackaddr_np(this_thread); // top of the stack
443440
size_t stack_size = pthread_get_stacksize_np(this_thread);
444-
_tstate->c_stack_top = (uintptr_t)stack_addr;
445-
_tstate->c_stack_hard_limit = _tstate->c_stack_top - stack_size;
446-
_tstate->c_stack_soft_limit = _tstate->c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES;
441+
*top = (uintptr_t)stack_addr;
442+
*base = ((uintptr_t)stack_addr) - stack_size;
447443
#else
448-
uintptr_t here_addr = _Py_get_machine_stack_pointer();
449-
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
450-
/// (on alpine at least) is much smaller than expected and imposes undue limits
451-
/// compared to the old stack size estimation. (We assume musl is not glibc.)
444+
/// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
445+
/// (on alpine at least) is much smaller than expected and imposes undue limits
446+
/// compared to the old stack size estimation. (We assume musl is not glibc.)
452447
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
453448
!defined(__NetBSD__) && (defined(__GLIBC__) || !defined(__linux__))
454449
size_t stack_size, guard_size;
@@ -461,26 +456,35 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
461456
err |= pthread_attr_destroy(&attr);
462457
}
463458
if (err == 0) {
464-
uintptr_t base = ((uintptr_t)stack_addr) + guard_size;
465-
_tstate->c_stack_top = base + stack_size;
466-
#ifdef _Py_THREAD_SANITIZER
467-
// Thread sanitizer crashes if we use a bit more than half the stack.
468-
_tstate->c_stack_soft_limit = base + (stack_size / 2);
469-
#else
470-
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
471-
#endif
472-
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
473-
assert(_tstate->c_stack_soft_limit < here_addr);
474-
assert(here_addr < _tstate->c_stack_top);
459+
*base = ((uintptr_t)stack_addr) + guard_size;
460+
*top = (uintptr_t)stack_addr + stack_size;
475461
return;
476462
}
477463
# endif
478-
_tstate->c_stack_top = _Py_SIZE_ROUND_UP(here_addr, 4096);
479-
_tstate->c_stack_soft_limit = _tstate->c_stack_top - Py_C_STACK_SIZE;
480-
_tstate->c_stack_hard_limit = _tstate->c_stack_top - (Py_C_STACK_SIZE + _PyOS_STACK_MARGIN_BYTES);
464+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
465+
uintptr_t top_addr = _Py_SIZE_ROUND_UP(here_addr, 4096);
466+
*top = top_addr;
467+
*base = top_addr - Py_C_STACK_SIZE;
481468
#endif
482469
}
483470

471+
void
472+
_Py_InitializeRecursionLimits(PyThreadState *tstate)
473+
{
474+
uintptr_t top;
475+
uintptr_t base;
476+
hardware_stack_limits(&top, &base);
477+
#ifdef _Py_THREAD_SANITIZER
478+
// Thread sanitizer crashes if we use more than half the stack.
479+
uintptr_t stacksize = top - base;
480+
base += stacksize/2;
481+
#endif
482+
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
483+
_tstate->c_stack_top = top;
484+
_tstate->c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES;
485+
_tstate->c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2;
486+
}
487+
484488
/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
485489
if the recursion_depth reaches recursion_limit. */
486490
int

0 commit comments

Comments
 (0)