unix: don't allow too small thread stack size (#3423)
uv_thread_create_ex() lets you set a stack size that is smaller than is safe. It enforces a lower bound of PTHREAD_STACK_MIN (when that constant is defined) but with musl libc that's still too small to receive signals on. Put the lower bound at 8192 or PTHREAD_STACK_MIN, whichever is greater. The same restriction was already in place for the _default_ stack size.
This commit is contained in:
parent
d5ed7f1256
commit
b5fa965bcb
@ -162,24 +162,6 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* On MacOS, threads other than the main thread are created with a reduced
|
|
||||||
* stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
|
|
||||||
*
|
|
||||||
* On Linux, threads created by musl have a much smaller stack than threads
|
|
||||||
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
|
|
||||||
*/
|
|
||||||
size_t uv__thread_stack_size(void) {
|
|
||||||
#if defined(__APPLE__) || defined(__linux__)
|
|
||||||
struct rlimit lim;
|
|
||||||
|
|
||||||
/* getrlimit() can fail on some aarch64 systems due to a glibc bug where
|
|
||||||
* the system call wrapper invokes the wrong system call. Don't treat
|
|
||||||
* that as fatal, just use the default stack size instead.
|
|
||||||
*/
|
|
||||||
if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) {
|
|
||||||
/* pthread_attr_setstacksize() expects page-aligned values. */
|
|
||||||
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
|
||||||
|
|
||||||
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
|
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
|
||||||
* too small to safely receive signals on.
|
* too small to safely receive signals on.
|
||||||
*
|
*
|
||||||
@ -191,12 +173,22 @@ size_t uv__thread_stack_size(void) {
|
|||||||
* is between 28 and 133 KB when compiling against glibc, depending
|
* is between 28 and 133 KB when compiling against glibc, depending
|
||||||
* on the architecture.
|
* on the architecture.
|
||||||
*/
|
*/
|
||||||
if (lim.rlim_cur >= 8192)
|
static size_t uv__min_stack_size(void) {
|
||||||
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
|
static const size_t min = 8192;
|
||||||
return lim.rlim_cur;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#ifdef PTHREAD_STACK_MIN /* Not defined on NetBSD. */
|
||||||
|
if (min < (size_t) PTHREAD_STACK_MIN)
|
||||||
|
return PTHREAD_STACK_MIN;
|
||||||
|
#endif /* PTHREAD_STACK_MIN */
|
||||||
|
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* On Linux, threads created by musl have a much smaller stack than threads
|
||||||
|
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
|
||||||
|
*/
|
||||||
|
static size_t uv__default_stack_size(void) {
|
||||||
#if !defined(__linux__)
|
#if !defined(__linux__)
|
||||||
return 0;
|
return 0;
|
||||||
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
|
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
|
||||||
@ -207,6 +199,34 @@ size_t uv__thread_stack_size(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* On MacOS, threads other than the main thread are created with a reduced
|
||||||
|
* stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
|
||||||
|
*/
|
||||||
|
size_t uv__thread_stack_size(void) {
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
struct rlimit lim;
|
||||||
|
|
||||||
|
/* getrlimit() can fail on some aarch64 systems due to a glibc bug where
|
||||||
|
* the system call wrapper invokes the wrong system call. Don't treat
|
||||||
|
* that as fatal, just use the default stack size instead.
|
||||||
|
*/
|
||||||
|
if (getrlimit(RLIMIT_STACK, &lim))
|
||||||
|
return uv__default_stack_size();
|
||||||
|
|
||||||
|
if (lim.rlim_cur == RLIM_INFINITY)
|
||||||
|
return uv__default_stack_size();
|
||||||
|
|
||||||
|
/* pthread_attr_setstacksize() expects page-aligned values. */
|
||||||
|
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
||||||
|
|
||||||
|
if (lim.rlim_cur >= (rlim_t) uv__min_stack_size())
|
||||||
|
return lim.rlim_cur;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return uv__default_stack_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||||
uv_thread_options_t params;
|
uv_thread_options_t params;
|
||||||
params.flags = UV_THREAD_NO_FLAGS;
|
params.flags = UV_THREAD_NO_FLAGS;
|
||||||
@ -222,6 +242,7 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
|||||||
pthread_attr_t attr_storage;
|
pthread_attr_t attr_storage;
|
||||||
size_t pagesize;
|
size_t pagesize;
|
||||||
size_t stack_size;
|
size_t stack_size;
|
||||||
|
size_t min_stack_size;
|
||||||
|
|
||||||
/* Used to squelch a -Wcast-function-type warning. */
|
/* Used to squelch a -Wcast-function-type warning. */
|
||||||
union {
|
union {
|
||||||
@ -239,10 +260,9 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
|||||||
pagesize = (size_t)getpagesize();
|
pagesize = (size_t)getpagesize();
|
||||||
/* Round up to the nearest page boundary. */
|
/* Round up to the nearest page boundary. */
|
||||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||||
#ifdef PTHREAD_STACK_MIN
|
min_stack_size = uv__min_stack_size();
|
||||||
if (stack_size < PTHREAD_STACK_MIN)
|
if (stack_size < min_stack_size)
|
||||||
stack_size = PTHREAD_STACK_MIN;
|
stack_size = min_stack_size;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack_size > 0) {
|
if (stack_size > 0) {
|
||||||
|
|||||||
@ -273,6 +273,11 @@ TEST_IMPL(thread_stack_size_explicit) {
|
|||||||
thread_check_stack, &options));
|
thread_check_stack, &options));
|
||||||
ASSERT(0 == uv_thread_join(&thread));
|
ASSERT(0 == uv_thread_join(&thread));
|
||||||
|
|
||||||
|
options.stack_size = 42;
|
||||||
|
ASSERT(0 == uv_thread_create_ex(&thread, &options,
|
||||||
|
thread_check_stack, &options));
|
||||||
|
ASSERT(0 == uv_thread_join(&thread));
|
||||||
|
|
||||||
#ifdef PTHREAD_STACK_MIN
|
#ifdef PTHREAD_STACK_MIN
|
||||||
options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */
|
options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */
|
||||||
ASSERT(0 == uv_thread_create_ex(&thread, &options,
|
ASSERT(0 == uv_thread_create_ex(&thread, &options,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user