Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Enable stack size limit detection on musl and other non-glibc Linux
platforms (like Android), instead of relying on a fixed stack size limit.
37 changes: 29 additions & 8 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count)
# define Py_C_STACK_SIZE 4000000
#endif

#ifdef HAVE_UNRELIABLE_PTHREAD_GETATTR_NP
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#endif

#if defined(__EMSCRIPTEN__)

// Temporary workaround to make `pthread_getattr_np` work on Emscripten.
Expand Down Expand Up @@ -142,14 +154,7 @@ hardware_stack_limits(uintptr_t *base, uintptr_t *top, uintptr_t sp)
*top = (uintptr_t)stack_addr;
*base = ((uintptr_t)stack_addr) - stack_size;
#else
// musl supports HAVE_PTHREAD_GETATTR_NP, but the resulting stack size
// (on alpine at least) is much smaller than expected and imposes undue
// limits compared to the old stack size estimation. musl doesn't give
// us a way to detect it, so we have to assume any non-glibc,
// non-Android Linux is musl and mustn't rely on pthread_getattr_np.
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
!defined(__NetBSD__) && \
(defined(__GLIBC__) || defined(__ANDROID__) || !defined(__linux__))
# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && !defined(__NetBSD__)
size_t stack_size, guard_size;
void *stack_addr;
pthread_attr_t attr;
Expand All @@ -160,6 +165,22 @@ hardware_stack_limits(uintptr_t *base, uintptr_t *top, uintptr_t sp)
err |= pthread_attr_destroy(&attr);
}
if (err == 0) {
# ifdef HAVE_UNRELIABLE_PTHREAD_GETATTR_NP
/* pthread_getattr_np on the main thread of a musl process reports a
* stack size based on the current stack rather than RLIMIT_STACK.
* New threads pass their size to pthread_attr_setstacksize and are
* reported correctly even on musl, so this fallback only applies to
* the main thread. */
if ((pid_t)syscall(SYS_gettid) == getpid()) {
struct rlimit rl;
if (getrlimit(RLIMIT_STACK, &rl) == 0 &&
rl.rlim_cur != RLIM_INFINITY &&
stack_size < rl.rlim_cur)
{
stack_size = rl.rlim_cur;
}
}
# endif
*base = ((uintptr_t)stack_addr) + guard_size;
*top = (uintptr_t)stack_addr + stack_size;
return;
Expand Down
1 change: 1 addition & 0 deletions Tools/build/check_capi_macros_ignored.txt
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ HAVE_UNAME
HAVE_UNISTD_H
HAVE_UNLINKAT
HAVE_UNLOCKPT
HAVE_UNRELIABLE_PTHREAD_GETATTR_NP
HAVE_UNSHARE
HAVE_USABLE_WCHAR_T
HAVE_UTIL_H
Expand Down
64 changes: 64 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -5587,6 +5587,41 @@ AC_CHECK_FUNCS([ \
PY_CHECK_FUNC_PRIVATE([freadlink], [@%:@include <unistd.h>])
PY_CHECK_FUNC_PRIVATE([strerror_r], [@%:@include <string.h>])

# Detect musl's behaviour of reporting the current allocated stack size for
# the main thread, rather than the max size, in pthread_getattr_np.
AS_IF([test "$ac_cv_func_pthread_getattr_np" = yes],
[AC_CACHE_CHECK([whether pthread_getattr_np reports the main thread stack reliably],
[ac_cv_unreliable_pthread_getattr_np],
[AC_RUN_IFELSE([AC_LANG_SOURCE([[
#define _GNU_SOURCE
#include <pthread.h>
#include <stdlib.h>
#include <sys/resource.h>

int main(void) {
pthread_attr_t attr;
void *stack_addr;
size_t stack_size, guard_size;
struct rlimit rl;

if (pthread_getattr_np(pthread_self(), &attr) != 0) return 1;
if (pthread_attr_getstack(&attr, &stack_addr, &stack_size) != 0 ||
pthread_attr_getguardsize(&attr, &guard_size) != 0) {
pthread_attr_destroy(&attr);
return 1;
}
pthread_attr_destroy(&attr);
if (getrlimit(RLIMIT_STACK, &rl) != 0) return 1;
if (rl.rlim_cur == RLIM_INFINITY) return 0;
return (stack_size >= rl.rlim_cur / 2) ? 0 : 1;
}
]])],
[ac_cv_unreliable_pthread_getattr_np=no],
[ac_cv_unreliable_pthread_getattr_np=yes],
[ac_cv_unreliable_pthread_getattr_np=no])])
AS_VAR_IF([ac_cv_unreliable_pthread_getattr_np], [yes],
[AC_DEFINE([HAVE_UNRELIABLE_PTHREAD_GETATTR_NP], [1],
[Define if pthread_getattr_np under-reports the main thread's stack size (musl behaviour).])])])

# os.statx uses Linux's statx function. AIX also has a function named statx,
# but it's unrelated. Check only on Linux (including Android).
Expand Down
4 changes: 4 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,10 @@
/* Define to 1 if you have the 'unlockpt' function. */
#undef HAVE_UNLOCKPT

/* Define if pthread_getattr_np under-reports the main thread's stack size
(musl behaviour). */
#undef HAVE_UNRELIABLE_PTHREAD_GETATTR_NP

/* Define to 1 if you have the 'unshare' function. */
#undef HAVE_UNSHARE

Expand Down
Loading