Skip to content

Commit af034fa

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

File tree

1 file changed

+28
-28
lines changed

1 file changed

+28
-28
lines changed

Python/ceval.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -438,31 +438,23 @@ 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.)
466458
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
467459
!defined(__NetBSD__) && (defined(__GLIBC__) || !defined(__linux__))
468460
size_t stack_size, guard_size;
@@ -475,26 +467,34 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
475467
err |= pthread_attr_destroy(&attr);
476468
}
477469
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);
470+
*base = ((uintptr_t)stack_addr) + guard_size;
471+
*top = (uintptr_t)stack_addr + stack_size;
489472
return;
490473
}
491474
# 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);
475+
uintptr_t here_addr = _Py_get_machine_stack_pointer();
476+
uintptr_t top_addr = _Py_SIZE_ROUND_UP(here_addr, 4096);
477+
*top = top_addr;
478+
*base = top_addr - Py_C_STACK_SIZE;
495479
#endif
496480
}
497481

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

0 commit comments

Comments
 (0)