/* This test causes an error in 3.10.1 and earlier versions like so: ==8336== Can't extend stack to 0x4033f98 during signal delivery for thread 2: ==8336== no stack segment The reason was that only AnonC segments were considered as stack segments. */ #include <assert.h> #include <fcntl.h> #include <pthread.h> #include <setjmp.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> static volatile char *lowest_j; static jmp_buf goback; static void sigsegv_handler(int signr) { longjmp(goback, 1); } static void bad_things_till_guard_page(void) { fprintf(stderr, "... doing bad things till guard page\n"); char j = 0; char *p = &j; for (;;) { j = j + *p; p = p - 400; lowest_j = p; } } static void say_something(void) { fprintf(stderr, "plugh\n"); } static void *child_func(void *arg) { if (setjmp(goback)) say_something(); else bad_things_till_guard_page(); return NULL; } int main(int argc, const char *argv[]) { /* We will discover the thread guard page using SEGV. So, prepare a handler. */ struct sigaction sa; sa.sa_handler = sigsegv_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGSEGV, &sa, NULL) != 0) perror("sigaction"); /* Create a file that will be used as stack for a pthread. */ size_t file_size = 1024 * 1024; const char file_name[] = "FILE"; int fd = open(file_name, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); assert(fd >= 0); void *p = calloc(file_size, 1); assert(p != 0); int written = write(fd, p, file_size); assert(written == file_size); close(fd); /* Create a file-based stack for the child. */ fd = open(file_name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); assert(fd >= 0); const size_t stack_size = 256 * 1024; assert(stack_size < file_size); void *stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); assert(stack != (void *)-1); pthread_attr_t attr; pthread_attr_init(&attr); int r = pthread_attr_setstack(&attr, stack, stack_size); assert(r == 0); /* Create child run. */ pthread_t child; r = pthread_create(&child, &attr, child_func, NULL); assert(r == 0); r = pthread_join(child, NULL); assert(r == 0); /* Remove file */ unlink(file_name); return 0; }