@@ -439,7 +439,7 @@ int pthread_attr_destroy(pthread_attr_t *a)
439439#endif
440440
441441static void
442- hardware_stack_limits (uintptr_t * top , uintptr_t * base )
442+ hardware_stack_limits (uintptr_t * base , uintptr_t * top )
443443{
444444#ifdef WIN32
445445 ULONG_PTR low , high ;
@@ -482,23 +482,86 @@ hardware_stack_limits(uintptr_t *top, uintptr_t *base)
482482#endif
483483}
484484
485- void
486- _Py_InitializeRecursionLimits (PyThreadState * tstate )
485+ static void
486+ tstate_set_stack (PyThreadState * tstate ,
487+ uintptr_t base , uintptr_t top )
487488{
488- uintptr_t top ;
489- uintptr_t base ;
490- hardware_stack_limits ( & top , & base );
489+ assert ( base < top ) ;
490+ assert (( top - base ) >= ( _PyOS_STACK_MARGIN_BYTES * 3 )) ;
491+
491492#ifdef _Py_THREAD_SANITIZER
492493 // Thread sanitizer crashes if we use more than half the stack.
493494 uintptr_t stacksize = top - base ;
494- base += stacksize / 2 ;
495+ base += stacksize / 2 ;
495496#endif
496497 _PyThreadStateImpl * _tstate = (_PyThreadStateImpl * )tstate ;
497498 _tstate -> c_stack_top = top ;
498499 _tstate -> c_stack_hard_limit = base + _PyOS_STACK_MARGIN_BYTES ;
499500 _tstate -> c_stack_soft_limit = base + _PyOS_STACK_MARGIN_BYTES * 2 ;
501+
502+ #ifndef NDEBUG
503+ // Sanity checks
504+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
505+ assert (ts -> c_stack_hard_limit <= ts -> c_stack_soft_limit );
506+ assert (ts -> c_stack_soft_limit < ts -> c_stack_top );
507+ #endif
508+ }
509+
510+
511+ void
512+ _Py_InitializeRecursionLimits (PyThreadState * tstate )
513+ {
514+ uintptr_t base , top ;
515+ hardware_stack_limits (& base , & top );
516+ assert (top != 0 );
517+
518+ tstate_set_stack (tstate , base , top );
519+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
520+ ts -> c_stack_init_base = base ;
521+ ts -> c_stack_init_top = top ;
522+
523+ // Test the stack pointer
524+ #if !defined(NDEBUG ) && !defined(__wasi__ )
525+ uintptr_t here_addr = _Py_get_machine_stack_pointer ();
526+ assert (ts -> c_stack_soft_limit < here_addr );
527+ assert (here_addr < ts -> c_stack_top );
528+ #endif
529+ }
530+
531+
532+ int
533+ PyUnstable_ThreadState_SetStack (PyThreadState * tstate ,
534+ void * stack_start_addr , size_t stack_size )
535+ {
536+ if (stack_size < (_PyOS_STACK_MARGIN_BYTES * 3 )) {
537+ PyErr_Format (PyExc_ValueError ,
538+ "stack_size must be at least %zu bytes" ,
539+ _PyOS_STACK_MARGIN_BYTES * 3 );
540+ return -1 ;
541+ }
542+
543+ uintptr_t base = (uintptr_t )stack_start_addr ;
544+ uintptr_t top = base + stack_size ;
545+ tstate_set_stack (tstate , base , top );
546+ return 0 ;
500547}
501548
549+
550+ void
551+ PyUnstable_ThreadState_ResetStack (PyThreadState * tstate )
552+ {
553+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )tstate ;
554+ if (ts -> c_stack_init_top != 0 ) {
555+ tstate_set_stack (tstate ,
556+ ts -> c_stack_init_base ,
557+ ts -> c_stack_init_top );
558+ return ;
559+ }
560+
561+ _Py_InitializeRecursionLimits (tstate );
562+ }
563+
564+
502565/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
503566 if the recursion_depth reaches recursion_limit. */
504567int
0 commit comments