17d4a28b986eaf98814c530a2074e117145b14d1fflorian/* This test causes an error in 3.10.1 and earlier versions like so: 27d4a28b986eaf98814c530a2074e117145b14d1fflorian 37d4a28b986eaf98814c530a2074e117145b14d1fflorian==8336== Can't extend stack to 0x4033f98 during signal delivery for thread 2: 47d4a28b986eaf98814c530a2074e117145b14d1fflorian==8336== no stack segment 57d4a28b986eaf98814c530a2074e117145b14d1fflorian 67d4a28b986eaf98814c530a2074e117145b14d1fflorian The reason was that only AnonC segments were considered as stack 77d4a28b986eaf98814c530a2074e117145b14d1fflorian segments. */ 87d4a28b986eaf98814c530a2074e117145b14d1fflorian 97d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <sys/mman.h> 107d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <sys/stat.h> 117d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <stdio.h> 127d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <pthread.h> 137d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <string.h> 147d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <stdlib.h> 157d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <assert.h> 167d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <setjmp.h> 177d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <signal.h> 187d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <fcntl.h> 197d4a28b986eaf98814c530a2074e117145b14d1fflorian#include <unistd.h> 207d4a28b986eaf98814c530a2074e117145b14d1fflorian 217d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic volatile char *lowest_j; 227d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic jmp_buf goback; 237d4a28b986eaf98814c530a2074e117145b14d1fflorian 247d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic void sigsegv_handler(int signr) 257d4a28b986eaf98814c530a2074e117145b14d1fflorian{ 267d4a28b986eaf98814c530a2074e117145b14d1fflorian longjmp(goback, 1); 277d4a28b986eaf98814c530a2074e117145b14d1fflorian} 287d4a28b986eaf98814c530a2074e117145b14d1fflorian 297d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic void bad_things_till_guard_page(void) 307d4a28b986eaf98814c530a2074e117145b14d1fflorian{ 317d4a28b986eaf98814c530a2074e117145b14d1fflorian fprintf(stderr, "... doing bad things till guard page\n"); 327d4a28b986eaf98814c530a2074e117145b14d1fflorian char j = 0; 337d4a28b986eaf98814c530a2074e117145b14d1fflorian char *p = &j; 347d4a28b986eaf98814c530a2074e117145b14d1fflorian 357d4a28b986eaf98814c530a2074e117145b14d1fflorian for (;;) { 367d4a28b986eaf98814c530a2074e117145b14d1fflorian j = j + *p; 377d4a28b986eaf98814c530a2074e117145b14d1fflorian p = p - 400; 387d4a28b986eaf98814c530a2074e117145b14d1fflorian lowest_j = p; 397d4a28b986eaf98814c530a2074e117145b14d1fflorian } 407d4a28b986eaf98814c530a2074e117145b14d1fflorian} 417d4a28b986eaf98814c530a2074e117145b14d1fflorian 427d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic void say_something(void) 437d4a28b986eaf98814c530a2074e117145b14d1fflorian{ 447d4a28b986eaf98814c530a2074e117145b14d1fflorian fprintf(stderr, "plugh\n"); 457d4a28b986eaf98814c530a2074e117145b14d1fflorian} 467d4a28b986eaf98814c530a2074e117145b14d1fflorian 477d4a28b986eaf98814c530a2074e117145b14d1fflorianstatic void* child_func ( void* arg ) 487d4a28b986eaf98814c530a2074e117145b14d1fflorian{ 497d4a28b986eaf98814c530a2074e117145b14d1fflorian if (setjmp(goback)) { 507d4a28b986eaf98814c530a2074e117145b14d1fflorian say_something(); 517d4a28b986eaf98814c530a2074e117145b14d1fflorian } else 527d4a28b986eaf98814c530a2074e117145b14d1fflorian bad_things_till_guard_page(); 537d4a28b986eaf98814c530a2074e117145b14d1fflorian 547d4a28b986eaf98814c530a2074e117145b14d1fflorian return NULL; 557d4a28b986eaf98814c530a2074e117145b14d1fflorian} 567d4a28b986eaf98814c530a2074e117145b14d1fflorian 577d4a28b986eaf98814c530a2074e117145b14d1fflorianint main(int argc, const char** argv) 587d4a28b986eaf98814c530a2074e117145b14d1fflorian{ 597d4a28b986eaf98814c530a2074e117145b14d1fflorian int r, fd; 607d4a28b986eaf98814c530a2074e117145b14d1fflorian 617d4a28b986eaf98814c530a2074e117145b14d1fflorian /* We will discover the thread guard page using SEGV. 627d4a28b986eaf98814c530a2074e117145b14d1fflorian So, prepare an handler. */ 637d4a28b986eaf98814c530a2074e117145b14d1fflorian struct sigaction sa; 647d4a28b986eaf98814c530a2074e117145b14d1fflorian sa.sa_handler = sigsegv_handler; 657d4a28b986eaf98814c530a2074e117145b14d1fflorian sigemptyset(&sa.sa_mask); 667d4a28b986eaf98814c530a2074e117145b14d1fflorian sa.sa_flags = 0; 677d4a28b986eaf98814c530a2074e117145b14d1fflorian if (sigaction (SIGSEGV, &sa, NULL) != 0) 687d4a28b986eaf98814c530a2074e117145b14d1fflorian perror("sigaction"); 697d4a28b986eaf98814c530a2074e117145b14d1fflorian 707d4a28b986eaf98814c530a2074e117145b14d1fflorian pthread_t child; 717d4a28b986eaf98814c530a2074e117145b14d1fflorian 727d4a28b986eaf98814c530a2074e117145b14d1fflorian /* Create a file that will be used as stack for a pthread. */ 737d4a28b986eaf98814c530a2074e117145b14d1fflorian const size_t file_size = 1024 * 1024; 747d4a28b986eaf98814c530a2074e117145b14d1fflorian const char file_name[] = "FILE"; 757d4a28b986eaf98814c530a2074e117145b14d1fflorian fd = open(file_name, O_CREAT|O_WRONLY, 767d4a28b986eaf98814c530a2074e117145b14d1fflorian S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 777d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(fd > 0); 787d4a28b986eaf98814c530a2074e117145b14d1fflorian void *p = malloc(file_size); 797d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(p != 0); 807d4a28b986eaf98814c530a2074e117145b14d1fflorian memset(p, 0, file_size); 817d4a28b986eaf98814c530a2074e117145b14d1fflorian int written = write(fd, p, file_size); 827d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(written == file_size); 837d4a28b986eaf98814c530a2074e117145b14d1fflorian close(fd); 847d4a28b986eaf98814c530a2074e117145b14d1fflorian 857d4a28b986eaf98814c530a2074e117145b14d1fflorian /* Create a file-based stack for the child */ 867d4a28b986eaf98814c530a2074e117145b14d1fflorian fd = open(file_name, O_CREAT|O_RDWR, 877d4a28b986eaf98814c530a2074e117145b14d1fflorian S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 887d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(fd > 0); 897d4a28b986eaf98814c530a2074e117145b14d1fflorian const size_t stack_size = 256 * 1024; 907d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(stack_size < file_size); 917d4a28b986eaf98814c530a2074e117145b14d1fflorian void *stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, 927d4a28b986eaf98814c530a2074e117145b14d1fflorian MAP_PRIVATE, fd, 0); 937d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(stack != (void *)-1); 947d4a28b986eaf98814c530a2074e117145b14d1fflorian pthread_attr_t attr; 957d4a28b986eaf98814c530a2074e117145b14d1fflorian pthread_attr_init(&attr); 967d4a28b986eaf98814c530a2074e117145b14d1fflorian r = pthread_attr_setstack(&attr, stack, stack_size); 977d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(r == 0); 987d4a28b986eaf98814c530a2074e117145b14d1fflorian 997d4a28b986eaf98814c530a2074e117145b14d1fflorian /* Create child run */ 1007d4a28b986eaf98814c530a2074e117145b14d1fflorian r = pthread_create(&child, &attr, child_func, NULL); 1017d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(r == 0); 1027d4a28b986eaf98814c530a2074e117145b14d1fflorian r = pthread_join(child, NULL); 1037d4a28b986eaf98814c530a2074e117145b14d1fflorian assert(r == 0); 1047d4a28b986eaf98814c530a2074e117145b14d1fflorian 1057d4a28b986eaf98814c530a2074e117145b14d1fflorian /* Remove file */ 1067d4a28b986eaf98814c530a2074e117145b14d1fflorian unlink(file_name); 1077d4a28b986eaf98814c530a2074e117145b14d1fflorian return 0; 1087d4a28b986eaf98814c530a2074e117145b14d1fflorian} 1097d4a28b986eaf98814c530a2074e117145b14d1fflorian 110