diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index cf24c9b..fbbbbb6 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -17,6 +17,22 @@ /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024) +/* If we use sigaltstack(2), do *not* use SIGSTKSZ as a stack size - It is 8k + and is not a sufficiently large stack for most use cases. + + On x86_64, the amount of stack space needed to save machine state with, say, + xsave or xsavec instructions is variable depending on the CPU, and can be up + to 2.5k. The state the kernel saves on the stack to handle signals can be + bigger again - well over 3k. Between chained signals, and dynamic linker + resolution overhead, we may easily use 3 such xsave state blocks on the + stack, and exceed the SIGSTKSZ 8k limit with ease + + This is our minimum size for the alternative stack. We also try and detect + the pthread stack size, and use that if we can find it, as we consider that + a reasonable default for creating new threads under normal circumstances. */ + +#define SIGALTSTACK_MIN_SIZE (1024 * 1024) + #define FAULTHANDLER_LATER #ifndef MS_WINDOWS @@ -1307,9 +1323,24 @@ _PyFaulthandler_Init(int enable) /* Try to allocate an alternate stack for faulthandler() signal handler to * be able to allocate memory on the stack, even on a stack overflow. If it - * fails, ignore the error. */ + * fails, ignore the error. + * + * For the stack size, if we have pthreads, start with the default reported + * from pthread_attr_getstacksize. Otherwise, start at SIGSTKSZ. In either event, + * make sure we have more than SIGALTSTACK_MIN_SIZE. (See comment above for + * caveats) */ stack.ss_flags = 0; - stack.ss_size = SIGSTKSZ; + +#ifdef HAVE_PTHREAD_H + pthread_attr_t attrs; + pthread_attr_init(&attrs); + (void)pthread_attr_getstacksize(&attrs, &stack.ss_size); + if (stack.ss_size == 0) +#endif + stack.ss_size = SIGSTKSZ; + if (stack.ss_size < SIGALTSTACK_MIN_SIZE) + stack.ss_size = SIGALTSTACK_MIN_SIZE; + stack.ss_sp = PyMem_Malloc(stack.ss_size); if (stack.ss_sp != NULL) { err = sigaltstack(&stack, &old_stack);