From 07d8e26be9cdcbf39acb03bdc6323d2702b34e0e Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 2 Jul 2018 18:53:34 +0900 Subject: [PATCH 1/7] bpo-33955: Support USE_STACKCHECK on macOS --- Doc/c-api/sys.rst | 6 +- Include/pythonrun.h | 5 ++ Lib/test/test_sys.py | 12 ++++ .../2018-07-02-18-53-31.bpo-33955.2FKRM2.rst | 2 + Python/pythonrun.c | 64 +++++++++++++++++++ 5 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-07-02-18-53-31.bpo-33955.2FKRM2.rst diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index c851ff66487d5c8..3f3124400dfef73 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -96,9 +96,9 @@ Operating System Utilities Return true when the interpreter runs out of stack space. This is a reliable check, but is only available when :const:`USE_STACKCHECK` is defined (currently - on Windows using the Microsoft Visual C++ compiler). :const:`USE_STACKCHECK` - will be defined automatically; you should never change the definition in your - own code. + on macOS and Windows using the Microsoft Visual C++ compiler). + :const:`USE_STACKCHECK` will be defined automatically; you should never + change the definition in your own code. .. c:function:: PyOS_sighandler_t PyOS_getsig(int i) diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 46091e09216330b..3a0403ed7f7ff33 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -199,6 +199,11 @@ PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState; #define USE_STACKCHECK #endif +#if defined(__APPLE__) +/* Enable stack checking under macOS */ +#define USE_STACKCHECK +#endif + #ifdef USE_STACKCHECK /* Check that we aren't overflowing our stack */ PyAPI_FUNC(int) PyOS_CheckStack(void); diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 947c935f34728ad..43e55407f0974a5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -234,6 +234,18 @@ def f(): finally: sys.setrecursionlimit(oldlimit) + @unittest.skipUnless(sys.platform == 'darwin', 'macOS only') + def test_setrecursion_with_memory_error(self): + oldlimit = sys.getrecursionlimit() + def f(): + f() + try: + sys.setrecursionlimit(1 << 30) + with self.assertRaisesRegex(MemoryError, r'Stack overflow'): + f() + finally: + sys.setrecursionlimit(oldlimit) + @test.support.cpython_only def test_setrecursionlimit_recursion_depth(self): # Issue #25274: Setting a low recursion limit must be blocked if the diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-07-02-18-53-31.bpo-33955.2FKRM2.rst b/Misc/NEWS.d/next/Core and Builtins/2018-07-02-18-53-31.bpo-33955.2FKRM2.rst new file mode 100644 index 000000000000000..ec46f0ce93a9629 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-07-02-18-53-31.bpo-33955.2FKRM2.rst @@ -0,0 +1,2 @@ +A interpreter on macOS system now supports USE_STACKCHECK. +The interpreter detects running out of stack space and raise MemoryError. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b68a0b5572a1b11..9dacf91c7e2cd53 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1649,6 +1649,70 @@ PyOS_CheckStack(void) #endif /* WIN32 && _MSC_VER */ +#if defined(__APPLE__) + +#define MAC_OS_10_9 13 +#define MAC_OS_10_10 14 +#define MAC_OS_10_11 15 + +#include + +/* + * Return non-zero when we run out of memory on the stack; zero otherwise. + */ + +__thread size_t last_remains = 0; /* Size of the last stack remain space */ +__thread size_t stack_space = 0; /* Size of a thread stack space */ + +int +PyOS_CheckStack(void) +{ + const pthread_t p_thread = pthread_self(); + const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(p_thread); + const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); + + if (stack_space == 0) { + if (pthread_main_np() == 1) { + // On macOS 10.09 - 10.11 pthread_get_stacksize_np + // returns wrong stack size on main thread. + // ref: https://github.com/rust-lang/rust/issues/43347#issuecomment-316783599 + // ref: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8020753 + struct utsname sysinfo; + uname(&sysinfo); + const int major_version = atoi(sysinfo.release); + if (major_version == MAC_OS_10_9 || + major_version == MAC_OS_10_10 || + major_version == MAC_OS_10_11) { + struct rlimit limit; + getrlimit(RLIMIT_STACK, &limit); + stack_space = limit.rlim_cur; + } else { + stack_space = pthread_get_stacksize_np(p_thread); + } + } else { + stack_space = pthread_get_stacksize_np(p_thread); + } + } + + const size_t remains = stack_space - (end - frame); + size_t required_stack_space = PYOS_STACK_MARGIN * sizeof(void*); + + // Estimate a required stack space based on last remain space. + if(last_remains > 0) { + if(last_remains > remains) { + required_stack_space = last_remains - remains; + } else if (last_remains < remains) { + required_stack_space = remains - last_remains; + } + } + last_remains = remains; + if (remains >= required_stack_space) { + return 0; + } + return 1; +} +#endif /* __APPLE__ */ + /* Alternate implementations can be added here... */ #endif /* USE_STACKCHECK */ From c967a08942051ec5fac89ac40f7bd49b353bcdf4 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 16 Nov 2018 00:35:07 +0900 Subject: [PATCH 2/7] bpo-33955: Remove the estimation code --- Lib/test/test_sys.py | 12 ------------ Python/pythonrun.c | 23 ++++------------------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 43e55407f0974a5..947c935f34728ad 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -234,18 +234,6 @@ def f(): finally: sys.setrecursionlimit(oldlimit) - @unittest.skipUnless(sys.platform == 'darwin', 'macOS only') - def test_setrecursion_with_memory_error(self): - oldlimit = sys.getrecursionlimit() - def f(): - f() - try: - sys.setrecursionlimit(1 << 30) - with self.assertRaisesRegex(MemoryError, r'Stack overflow'): - f() - finally: - sys.setrecursionlimit(oldlimit) - @test.support.cpython_only def test_setrecursionlimit_recursion_depth(self): # Issue #25274: Setting a low recursion limit must be blocked if the diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 9dacf91c7e2cd53..f0e0c6a3fdd0d96 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1661,15 +1661,13 @@ PyOS_CheckStack(void) * Return non-zero when we run out of memory on the stack; zero otherwise. */ -__thread size_t last_remains = 0; /* Size of the last stack remain space */ -__thread size_t stack_space = 0; /* Size of a thread stack space */ - int PyOS_CheckStack(void) { const pthread_t p_thread = pthread_self(); const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(p_thread); const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); + size_t stack_space = 0; if (stack_space == 0) { if (pthread_main_np() == 1) { @@ -1693,24 +1691,11 @@ PyOS_CheckStack(void) stack_space = pthread_get_stacksize_np(p_thread); } } - const size_t remains = stack_space - (end - frame); - size_t required_stack_space = PYOS_STACK_MARGIN * sizeof(void*); - - // Estimate a required stack space based on last remain space. - if(last_remains > 0) { - if(last_remains > remains) { - required_stack_space = last_remains - remains; - } else if (last_remains < remains) { - required_stack_space = remains - last_remains; - } - } - last_remains = remains; - if (remains >= required_stack_space) { - return 0; - } - return 1; + const size_t required_stack_space = PYOS_STACK_MARGIN * sizeof(void*); + return remains < PTHREAD_STACK_MIN; } + #endif /* __APPLE__ */ /* Alternate implementations can be added here... */ From d4465d6179ba70c153e6cf13acf9c31b1321da7e Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Tue, 17 Dec 2019 13:09:43 +0900 Subject: [PATCH 3/7] bpo-33955: Apply code review --- Doc/whatsnew/3.9.rst | 4 +- Include/internal/pycore_pystate.h | 4 ++ Lib/test/test_sys.py | 12 +++++ Python/pythonrun.c | 82 ++++++++++++++++++++----------- 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index a686d640ae94bff..667cecc89d0094b 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -69,7 +69,9 @@ Summary -- Release highlights New Features ============ - +* An interpreter on macOS system now supports ``USE_STACKCHECK``. The interpreter + detects running out of stack space and raise :class:`MemoryError`. + (Contributed by Dong-hee Na in :issue:`33955`.) Other Language Changes diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index b78ed69042527e3..f4faee504a0dc6e 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -92,6 +92,10 @@ struct _is { or the size specified by the THREAD_STACK_SIZE macro. */ /* Used in Python/thread.c. */ size_t pythread_stacksize; +#if defined(USE_STACKCHECK) && defined(__APPLE__) + size_t stack_check_size; + size_t last_stack_remain; +#endif PyObject *codec_search_path; PyObject *codec_search_cache; diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 947c935f34728ad..08347f74c7c34f2 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -211,6 +211,18 @@ def test_recursionlimit(self): self.assertEqual(sys.getrecursionlimit(), 10000) sys.setrecursionlimit(oldlimit) + @unittest.skipUnless(sys.platform == 'darwin', 'macOS only') + def test_setrecursion_with_memory_error(self): + oldlimit = sys.getrecursionlimit() + def f(): + f() + try: + sys.setrecursionlimit(1 << 30) + with self.assertRaisesRegex(MemoryError, r'Stack overflow'): + f() + finally: + sys.setrecursionlimit(oldlimit) + def test_recursionlimit_recovery(self): if hasattr(sys, 'gettrace') and sys.gettrace(): self.skipTest('fatal error if run with a trace function') diff --git a/Python/pythonrun.c b/Python/pythonrun.c index f0e0c6a3fdd0d96..2195bcecdcb5593 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1657,43 +1657,67 @@ PyOS_CheckStack(void) #include +size_t +Get_Stack_Check_Size(pthread_t *thread_self) +{ + size_t stack_space = 0; + if (pthread_main_np() == 1) { + // On macOS 10.09 - 10.11 pthread_get_stacksize_np + // returns wrong stack size on main thread. + // ref: https://github.com/rust-lang/rust/issues/43347#issuecomment-316783599 + // ref: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8020753 + struct utsname sysinfo; + uname(&sysinfo); + const int major_version = atoi(sysinfo.release); + if (major_version == MAC_OS_10_9 || + major_version == MAC_OS_10_10 || + major_version == MAC_OS_10_11) { + struct rlimit limit; + getrlimit(RLIMIT_STACK, &limit); + stack_space = limit.rlim_cur; + } else { + stack_space = pthread_get_stacksize_np(*thread_self); + } + } else { + stack_space = pthread_get_stacksize_np(*thread_self); + } + return stack_space; +} + +void +Init_Stack_Status(void) { + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->interp->stack_check_size == 0) { + const pthread_t thread_self = pthread_self(); + tstate->interp->stack_check_size = Get_Stack_Check_Size(&thread_self); + } +} + /* * Return non-zero when we run out of memory on the stack; zero otherwise. */ - int PyOS_CheckStack(void) { - const pthread_t p_thread = pthread_self(); - const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(p_thread); + Init_Stack_Status(); + PyThreadState *tstate = _PyThreadState_GET(); + const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(pthread_self()); const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); - size_t stack_space = 0; - - if (stack_space == 0) { - if (pthread_main_np() == 1) { - // On macOS 10.09 - 10.11 pthread_get_stacksize_np - // returns wrong stack size on main thread. - // ref: https://github.com/rust-lang/rust/issues/43347#issuecomment-316783599 - // ref: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8020753 - struct utsname sysinfo; - uname(&sysinfo); - const int major_version = atoi(sysinfo.release); - if (major_version == MAC_OS_10_9 || - major_version == MAC_OS_10_10 || - major_version == MAC_OS_10_11) { - struct rlimit limit; - getrlimit(RLIMIT_STACK, &limit); - stack_space = limit.rlim_cur; - } else { - stack_space = pthread_get_stacksize_np(p_thread); - } - } else { - stack_space = pthread_get_stacksize_np(p_thread); - } - } + const size_t stack_space = tstate->interp->stack_check_size; const size_t remains = stack_space - (end - frame); - const size_t required_stack_space = PYOS_STACK_MARGIN * sizeof(void*); - return remains < PTHREAD_STACK_MIN; + + size_t required_stack_space = 0; + if (remains > tstate->interp->last_stack_remain) { + required_stack_space = remains - tstate->interp->last_stack_remain; + } else { + required_stack_space = tstate->interp->last_stack_remain - remains; + } + + tstate->interp->last_stack_remain = remains; + if (remains >= required_stack_space) { + return 0; + } + return 1; } #endif /* __APPLE__ */ From c8fe4610024ecd1f92affab52b0c92f370647741 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Tue, 17 Dec 2019 18:45:32 +0900 Subject: [PATCH 4/7] bpo-33955: Apply code review --- Python/pythonrun.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 2195bcecdcb5593..83bb6e80076d858 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1658,7 +1658,7 @@ PyOS_CheckStack(void) #include size_t -Get_Stack_Check_Size(pthread_t *thread_self) +Get_Stack_Check_Size(const pthread_t *thread_self) { size_t stack_space = 0; if (pthread_main_np() == 1) { @@ -1685,8 +1685,7 @@ Get_Stack_Check_Size(pthread_t *thread_self) } void -Init_Stack_Status(void) { - PyThreadState *tstate = _PyThreadState_GET(); +Init_Stack_Status(PyThreadState *tstate) { if (tstate->interp->stack_check_size == 0) { const pthread_t thread_self = pthread_self(); tstate->interp->stack_check_size = Get_Stack_Check_Size(&thread_self); @@ -1699,8 +1698,8 @@ Init_Stack_Status(void) { int PyOS_CheckStack(void) { - Init_Stack_Status(); PyThreadState *tstate = _PyThreadState_GET(); + Init_Stack_Status(tstate); const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(pthread_self()); const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); const size_t stack_space = tstate->interp->stack_check_size; From 6a3879c8728d732d6da2e33eb159acd670656b7d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 18 Dec 2019 00:52:25 +0900 Subject: [PATCH 5/7] bpo-33955: Fix --- Include/cpython/pystate.h | 3 ++- Include/internal/pycore_pystate.h | 4 ---- Python/pystate.c | 2 +- Python/pythonrun.c | 16 +++++++++------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index d1792575c973789..6a3c902b729529d 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -134,7 +134,8 @@ struct _ts { /* Unique thread state id. */ uint64_t id; - + size_t stack_space; + size_t last_stack_remain; /* XXX signal handlers should also be here */ }; diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index f4faee504a0dc6e..b78ed69042527e3 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -92,10 +92,6 @@ struct _is { or the size specified by the THREAD_STACK_SIZE macro. */ /* Used in Python/thread.c. */ size_t pythread_stacksize; -#if defined(USE_STACKCHECK) && defined(__APPLE__) - size_t stack_check_size; - size_t last_stack_remain; -#endif PyObject *codec_search_path; PyObject *codec_search_cache; diff --git a/Python/pystate.c b/Python/pystate.c index d792380de464989..0a5f14d2925fad6 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -607,7 +607,7 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->context_ver = 1; tstate->id = ++interp->tstate_next_unique_id; - + tstate->stack_space = 0; if (init) { _PyThreadState_Init(tstate); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 83bb6e80076d858..b410ee0e52edd67 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1686,9 +1686,11 @@ Get_Stack_Check_Size(const pthread_t *thread_self) void Init_Stack_Status(PyThreadState *tstate) { - if (tstate->interp->stack_check_size == 0) { + if (tstate->stack_space == 0) { const pthread_t thread_self = pthread_self(); - tstate->interp->stack_check_size = Get_Stack_Check_Size(&thread_self); + size_t stack_space = Get_Stack_Check_Size(&thread_self); + tstate->stack_space = stack_space; + tstate->last_stack_remain = stack_space; } } @@ -1702,17 +1704,17 @@ PyOS_CheckStack(void) Init_Stack_Status(tstate); const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(pthread_self()); const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); - const size_t stack_space = tstate->interp->stack_check_size; + const size_t stack_space = tstate->stack_space; const size_t remains = stack_space - (end - frame); size_t required_stack_space = 0; - if (remains > tstate->interp->last_stack_remain) { - required_stack_space = remains - tstate->interp->last_stack_remain; + if (remains > tstate->last_stack_remain) { + required_stack_space = remains - tstate->last_stack_remain; } else { - required_stack_space = tstate->interp->last_stack_remain - remains; + required_stack_space = tstate->last_stack_remain - remains; } - tstate->interp->last_stack_remain = remains; + tstate->last_stack_remain = remains; if (remains >= required_stack_space) { return 0; } From 79b10e602f9adbbc76a848cff07363e12ae66183 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 18 Dec 2019 01:26:14 +0900 Subject: [PATCH 6/7] bpo-33955: lint --- Python/pythonrun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b410ee0e52edd67..cd390e180472ac5 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1660,8 +1660,8 @@ PyOS_CheckStack(void) size_t Get_Stack_Check_Size(const pthread_t *thread_self) { - size_t stack_space = 0; - if (pthread_main_np() == 1) { + size_t stack_space = 0; + if (pthread_main_np() == 1) { // On macOS 10.09 - 10.11 pthread_get_stacksize_np // returns wrong stack size on main thread. // ref: https://github.com/rust-lang/rust/issues/43347#issuecomment-316783599 From 60c3f0f0f97e3768246bce6ec192e37615b20d01 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 13 Jan 2020 17:40:41 +0900 Subject: [PATCH 7/7] bpo-33955: Apply codereview --- Doc/whatsnew/3.9.rst | 1 + Include/cpython/pystate.h | 3 +++ Python/pystate.c | 3 +++ Python/pythonrun.c | 36 ++++++++++++++++-------------------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 667cecc89d0094b..a9577bdd899f1a3 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -69,6 +69,7 @@ Summary -- Release highlights New Features ============ + * An interpreter on macOS system now supports ``USE_STACKCHECK``. The interpreter detects running out of stack space and raise :class:`MemoryError`. (Contributed by Dong-hee Na in :issue:`33955`.) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 6a3c902b729529d..2b1c85fac868d76 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -134,8 +134,11 @@ struct _ts { /* Unique thread state id. */ uint64_t id; + +#if defined(__APPLE__) size_t stack_space; size_t last_stack_remain; +#endif /* XXX signal handlers should also be here */ }; diff --git a/Python/pystate.c b/Python/pystate.c index 0a5f14d2925fad6..7bbb5ebfd91cd1a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -607,7 +607,10 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->context_ver = 1; tstate->id = ++interp->tstate_next_unique_id; +#if defined(__APPLE__) tstate->stack_space = 0; + tstate->last_stack_remain = 0; +#endif if (init) { _PyThreadState_Init(tstate); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index cd390e180472ac5..03d395225c03756 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1657,10 +1657,10 @@ PyOS_CheckStack(void) #include -size_t +static size_t Get_Stack_Check_Size(const pthread_t *thread_self) { - size_t stack_space = 0; + size_t stack_space; if (pthread_main_np() == 1) { // On macOS 10.09 - 10.11 pthread_get_stacksize_np // returns wrong stack size on main thread. @@ -1675,25 +1675,17 @@ Get_Stack_Check_Size(const pthread_t *thread_self) struct rlimit limit; getrlimit(RLIMIT_STACK, &limit); stack_space = limit.rlim_cur; - } else { + } + else { stack_space = pthread_get_stacksize_np(*thread_self); } - } else { + } + else { stack_space = pthread_get_stacksize_np(*thread_self); } return stack_space; } -void -Init_Stack_Status(PyThreadState *tstate) { - if (tstate->stack_space == 0) { - const pthread_t thread_self = pthread_self(); - size_t stack_space = Get_Stack_Check_Size(&thread_self); - tstate->stack_space = stack_space; - tstate->last_stack_remain = stack_space; - } -} - /* * Return non-zero when we run out of memory on the stack; zero otherwise. */ @@ -1701,16 +1693,21 @@ int PyOS_CheckStack(void) { PyThreadState *tstate = _PyThreadState_GET(); - Init_Stack_Status(tstate); + if (tstate->stack_space == 0) { + const pthread_t thread_self = pthread_self(); + size_t stack_space = Get_Stack_Check_Size(&thread_self); + tstate->stack_space = stack_space; + tstate->last_stack_remain = stack_space; + } const uintptr_t end = (uintptr_t)pthread_get_stackaddr_np(pthread_self()); const uintptr_t frame = (uintptr_t)__builtin_frame_address(0); - const size_t stack_space = tstate->stack_space; - const size_t remains = stack_space - (end - frame); + const size_t remains = tstate->stack_space - (end - frame); + size_t required_stack_space; - size_t required_stack_space = 0; if (remains > tstate->last_stack_remain) { required_stack_space = remains - tstate->last_stack_remain; - } else { + } + else { required_stack_space = tstate->last_stack_remain - remains; } @@ -1720,7 +1717,6 @@ PyOS_CheckStack(void) } return 1; } - #endif /* __APPLE__ */ /* Alternate implementations can be added here... */