@@ -436,24 +436,26 @@ int pthread_attr_destroy(pthread_attr_t *a)
436436
437437#endif
438438
439-
440- void
441- _Py_InitializeRecursionLimits (PyThreadState * tstate )
439+ static void
440+ hardware_stack_limits (uintptr_t * base , uintptr_t * top )
442441{
443- _PyThreadStateImpl * _tstate = (_PyThreadStateImpl * )tstate ;
444442#ifdef WIN32
445443 ULONG_PTR low , high ;
446444 GetCurrentThreadStackLimits (& low , & high );
447- _tstate -> c_stack_top = (uintptr_t )high ;
445+ * top = (uintptr_t )high ;
448446 ULONG guarantee = 0 ;
449447 SetThreadStackGuarantee (& guarantee );
450- _tstate -> c_stack_hard_limit = ((uintptr_t )low ) + guarantee + _PyOS_STACK_MARGIN_BYTES ;
451- _tstate -> c_stack_soft_limit = _tstate -> c_stack_hard_limit + _PyOS_STACK_MARGIN_BYTES ;
448+ * base = (uintptr_t )low + guarantee ;
449+ #elif defined(__APPLE__ )
450+ pthread_t this_thread = pthread_self ();
451+ void * stack_addr = pthread_get_stackaddr_np (this_thread ); // top of the stack
452+ size_t stack_size = pthread_get_stacksize_np (this_thread );
453+ * top = (uintptr_t )stack_addr ;
454+ * base = ((uintptr_t )stack_addr ) - stack_size ;
452455#else
453- uintptr_t here_addr = _Py_get_machine_stack_pointer ();
454- /// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
455- /// (on alpine at least) is much smaller than expected and imposes undue limits
456- /// compared to the old stack size estimation. (We assume musl is not glibc.)
456+ /// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
457+ /// (on alpine at least) is much smaller than expected and imposes undue limits
458+ /// compared to the old stack size estimation. (We assume musl is not glibc.)
457459# if defined(HAVE_PTHREAD_GETATTR_NP ) && !defined(_AIX ) && \
458460 !defined(__NetBSD__ ) && (defined(__GLIBC__ ) || !defined(__linux__ ))
459461 size_t stack_size , guard_size ;
@@ -466,38 +468,106 @@ _Py_InitializeRecursionLimits(PyThreadState *tstate)
466468 err |= pthread_attr_destroy (& attr );
467469 }
468470 if (err == 0 ) {
469- uintptr_t base = ((uintptr_t )stack_addr ) + guard_size ;
470- uintptr_t top = base + stack_size ;
471- # ifdef _Py_THREAD_SANITIZER
472- // Thread sanitizer crashes if we use a bit more than half the stack.
473- # if _Py_STACK_GROWS_DOWN
474- base += stack_size / 2 ;
475- # else
476- top -= stack_size / 2 ;
477- # endif
478- # endif
479- # if _Py_STACK_GROWS_DOWN
480- _tstate -> c_stack_top = top ;
481- _tstate -> c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES ;
482- _tstate -> c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2 ;
483- assert (_tstate -> c_stack_soft_limit < here_addr );
484- assert (here_addr < _tstate -> c_stack_top );
485- # else
486- _tstate -> c_stack_top = base ;
487- _tstate -> c_stack_hard_limit = top - _PyOS_STACK_MARGIN_BYTES ;
488- _tstate -> c_stack_soft_limit = top - _PyOS_STACK_MARGIN_BYTES * 2 ;
489- assert (here_addr > base );
490- assert (here_addr < _tstate -> c_stack_soft_limit );
491- # endif
471+ * base = ((uintptr_t )stack_addr ) + guard_size ;
472+ * top = (uintptr_t )stack_addr + stack_size ;
492473 return ;
493474 }
494475# endif
495- _tstate -> c_stack_top = _Py_SIZE_ROUND_UP (here_addr , 4096 );
496- _tstate -> c_stack_soft_limit = _tstate -> c_stack_top - Py_C_STACK_SIZE ;
497- _tstate -> c_stack_hard_limit = _tstate -> c_stack_top - (Py_C_STACK_SIZE + _PyOS_STACK_MARGIN_BYTES );
476+ uintptr_t here_addr = _Py_get_machine_stack_pointer ();
477+ uintptr_t top_addr = _Py_SIZE_ROUND_UP (here_addr , 4096 );
478+ * top = top_addr ;
479+ * base = top_addr - Py_C_STACK_SIZE ;
480+ #endif
481+ }
482+
483+ static void
484+ tstate_set_stack (PyThreadState * tstate ,
485+ uintptr_t base , uintptr_t top )
486+ {
487+ assert (base < top );
488+ assert ((top - base ) >= _PyOS_MIN_STACK_SIZE );
489+
490+ #ifdef _Py_THREAD_SANITIZER
491+ // Thread sanitizer crashes if we use more than half the stack.
492+ uintptr_t stacksize = top - base ;
493+ # if _Py_STACK_GROWS_DOWN
494+ base += stacksize / 2 ;
495+ # else
496+ top -= stacksize / 2 ;
497+ # endif
498+ #endif
499+ _PyThreadStateImpl * _tstate = (_PyThreadStateImpl * )tstate ;
500+ #if _Py_STACK_GROWS_DOWN
501+ _tstate -> c_stack_top = top ;
502+ _tstate -> c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES ;
503+ _tstate -> c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2 ;
504+ # ifndef NDEBUG
505+ // Sanity checks
506+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
507+ assert (ts -> c_stack_hard_limit <= ts -> c_stack_soft_limit );
508+ assert (ts -> c_stack_soft_limit < ts -> c_stack_top );
509+ # endif
510+ #else
511+ _tstate -> c_stack_top = base ;
512+ _tstate -> c_stack_hard_limit = top - _PyOS_STACK_MARGIN_BYTES ;
513+ _tstate -> c_stack_soft_limit = top - _PyOS_STACK_MARGIN_BYTES * 2 ;
514+ # ifndef NDEBUG
515+ // Sanity checks
516+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
517+ assert (ts -> c_stack_hard_limit >= ts -> c_stack_soft_limit );
518+ assert (ts -> c_stack_soft_limit > ts -> c_stack_top );
519+ # endif
498520#endif
499521}
500522
523+
524+ void
525+ _Py_InitializeRecursionLimits (PyThreadState * tstate )
526+ {
527+ uintptr_t base , top ;
528+ hardware_stack_limits (& base , & top );
529+ assert (top != 0 );
530+
531+ tstate_set_stack (tstate , base , top );
532+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
533+ ts -> c_stack_init_base = base ;
534+ ts -> c_stack_init_top = top ;
535+ }
536+
537+
538+ int
539+ PyUnstable_ThreadState_SetStackProtection (PyThreadState * tstate ,
540+ void * stack_start_addr , size_t stack_size )
541+ {
542+ if (stack_size < _PyOS_MIN_STACK_SIZE ) {
543+ PyErr_Format (PyExc_ValueError ,
544+ "stack_size must be at least %zu bytes" ,
545+ _PyOS_MIN_STACK_SIZE );
546+ return -1 ;
547+ }
548+
549+ uintptr_t base = (uintptr_t )stack_start_addr ;
550+ uintptr_t top = base + stack_size ;
551+ tstate_set_stack (tstate , base , top );
552+ return 0 ;
553+ }
554+
555+
556+ void
557+ PyUnstable_ThreadState_ResetStackProtection (PyThreadState * tstate )
558+ {
559+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
560+ if (ts -> c_stack_init_top != 0 ) {
561+ tstate_set_stack (tstate ,
562+ ts -> c_stack_init_base ,
563+ ts -> c_stack_init_top );
564+ return ;
565+ }
566+
567+ _Py_InitializeRecursionLimits (tstate );
568+ }
569+
570+
501571/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
502572 if the recursion_depth reaches recursion_limit. */
503573int
0 commit comments