@@ -344,9 +344,11 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count)
344344 _Py_InitializeRecursionLimits (tstate );
345345 }
346346#if _Py_STACK_GROWS_DOWN
347- return here_addr <= _tstate -> c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES ;
347+ return here_addr <= _tstate -> c_stack_soft_limit + margin_count * _PyOS_STACK_MARGIN_BYTES &&
348+ here_addr >= _tstate -> c_stack_soft_limit - 2 * _PyOS_STACK_MARGIN_BYTES ;
348349#else
349- return here_addr > _tstate -> c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES ;
350+ return here_addr > _tstate -> c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES &&
351+ here_addr <= _tstate -> c_stack_soft_limit + 2 * _PyOS_STACK_MARGIN_BYTES ;
350352#endif
351353}
352354
@@ -437,7 +439,7 @@ int pthread_attr_destroy(pthread_attr_t *a)
437439#endif
438440
439441static void
440- hardware_stack_limits (uintptr_t * base , uintptr_t * top )
442+ hardware_stack_limits (uintptr_t * base , uintptr_t * top , uintptr_t sp )
441443{
442444#ifdef WIN32
443445 ULONG_PTR low , high ;
@@ -473,10 +475,19 @@ hardware_stack_limits(uintptr_t *base, uintptr_t *top)
473475 return ;
474476 }
475477# endif
476- uintptr_t here_addr = _Py_get_machine_stack_pointer ();
477- uintptr_t top_addr = _Py_SIZE_ROUND_UP (here_addr , 4096 );
478+ // Add some space for caller function then round to minimum page size
479+ // This is a guess at the top of the stack, but should be a reasonably
480+ // good guess if called from _PyThreadState_Attach when creating a thread.
481+ // If the thread is attached deep in a call stack, then the guess will be poor.
482+ #if _Py_STACK_GROWS_DOWN
483+ uintptr_t top_addr = _Py_SIZE_ROUND_UP (sp + 8 * sizeof (void * ), SYSTEM_PAGE_SIZE );
478484 * top = top_addr ;
479485 * base = top_addr - Py_C_STACK_SIZE ;
486+ # else
487+ uintptr_t base_addr = _Py_SIZE_ROUND_DOWN (sp - 8 * sizeof (void * ), SYSTEM_PAGE_SIZE );
488+ * base = base_addr ;
489+ * top = base_addr + Py_C_STACK_SIZE ;
490+ #endif
480491#endif
481492}
482493
@@ -505,28 +516,20 @@ tstate_set_stack(PyThreadState *tstate,
505516#endif
506517}
507518
508-
509519void
510520_Py_InitializeRecursionLimits (PyThreadState * tstate )
511521{
512522 uintptr_t base , top ;
513- hardware_stack_limits (& base , & top );
523+ uintptr_t here_addr = _Py_get_machine_stack_pointer ();
524+ hardware_stack_limits (& base , & top , here_addr );
514525 assert (top != 0 );
515526
516527 tstate_set_stack (tstate , base , top );
517528 _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
518529 ts -> c_stack_init_base = base ;
519530 ts -> c_stack_init_top = top ;
520-
521- // Test the stack pointer
522- #if !defined(NDEBUG ) && !defined(__wasi__ )
523- uintptr_t here_addr = _Py_get_machine_stack_pointer ();
524- assert (ts -> c_stack_soft_limit < here_addr );
525- assert (here_addr < ts -> c_stack_top );
526- #endif
527531}
528532
529-
530533int
531534PyUnstable_ThreadState_SetStackProtection (PyThreadState * tstate ,
532535 void * stack_start_addr , size_t stack_size )
@@ -561,7 +564,7 @@ PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)
561564
562565
563566/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
564- if the recursion_depth reaches recursion_limit . */
567+ if the stack pointer is between the stack base and c_stack_hard_limit . */
565568int
566569_Py_CheckRecursiveCall (PyThreadState * tstate , const char * where )
567570{
@@ -570,10 +573,12 @@ _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
570573 assert (_tstate -> c_stack_soft_limit != 0 );
571574 assert (_tstate -> c_stack_hard_limit != 0 );
572575#if _Py_STACK_GROWS_DOWN
576+ assert (here_addr >= _tstate -> c_stack_hard_limit - _PyOS_STACK_MARGIN_BYTES );
573577 if (here_addr < _tstate -> c_stack_hard_limit ) {
574578 /* Overflowing while handling an overflow. Give up. */
575579 int kbytes_used = (int )(_tstate -> c_stack_top - here_addr )/1024 ;
576580#else
581+ assert (here_addr <= _tstate -> c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES );
577582 if (here_addr > _tstate -> c_stack_hard_limit ) {
578583 /* Overflowing while handling an overflow. Give up. */
579584 int kbytes_used = (int )(here_addr - _tstate -> c_stack_top )/1024 ;
0 commit comments