Home | History | Annotate | Download | only in linux
      1 /* This test causes an error in 3.10.1 and earlier versions like so:
      2 
      3 ==8336== Can't extend stack to 0x4033f98 during signal delivery for thread 2:
      4 ==8336==   no stack segment
      5 
      6   The reason was that only AnonC segments were considered as stack
      7   segments. */
      8 
      9 #include <sys/mman.h>
     10 #include <sys/stat.h>
     11 #include <stdio.h>
     12 #include <pthread.h>
     13 #include <string.h>
     14 #include <stdlib.h>
     15 #include <assert.h>
     16 #include <setjmp.h>
     17 #include <signal.h>
     18 #include <fcntl.h>
     19 #include <unistd.h>
     20 
     21 static volatile char *lowest_j;
     22 static jmp_buf goback;
     23 
     24 static void sigsegv_handler(int signr)
     25 {
     26    longjmp(goback, 1);
     27 }
     28 
     29 static void bad_things_till_guard_page(void)
     30 {
     31    fprintf(stderr, "... doing bad things till guard page\n");
     32    char j = 0;
     33    char *p = &j;
     34 
     35    for (;;) {
     36       j = j + *p;
     37       p = p - 400;
     38       lowest_j = p;
     39    }
     40 }
     41 
     42 static void say_something(void)
     43 {
     44   fprintf(stderr, "plugh\n");
     45 }
     46 
     47 static void* child_func ( void* arg )
     48 {
     49    if (setjmp(goback)) {
     50       say_something();
     51    } else
     52       bad_things_till_guard_page();
     53 
     54    return NULL;
     55 }
     56 
     57 int main(int argc, const char** argv)
     58 {
     59    int r, fd;
     60 
     61    /* We will discover the thread guard page using SEGV.
     62       So, prepare an handler. */
     63    struct sigaction sa;
     64    sa.sa_handler = sigsegv_handler;
     65    sigemptyset(&sa.sa_mask);
     66    sa.sa_flags = 0;
     67    if (sigaction (SIGSEGV, &sa, NULL) != 0)
     68       perror("sigaction");
     69 
     70    pthread_t child;
     71 
     72    /* Create a file that will be used as stack for a pthread.  */
     73    const size_t file_size = 1024 * 1024;
     74    const char file_name[] = "FILE";
     75    fd = open(file_name, O_CREAT|O_WRONLY,
     76              S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
     77    assert(fd > 0);
     78    void *p = malloc(file_size);
     79    assert(p != 0);
     80    memset(p, 0, file_size);
     81    int written = write(fd, p, file_size);
     82    assert(written == file_size);
     83    close(fd);
     84 
     85    /* Create a file-based stack for the child */
     86    fd = open(file_name, O_CREAT|O_RDWR,
     87              S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
     88    assert(fd > 0);
     89    const size_t stack_size = 256 * 1024;
     90    assert(stack_size < file_size);
     91    void *stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE,
     92                       MAP_PRIVATE, fd, 0);
     93    assert(stack != (void *)-1);
     94    pthread_attr_t attr;
     95    pthread_attr_init(&attr);
     96    r = pthread_attr_setstack(&attr, stack, stack_size);
     97    assert(r == 0);
     98 
     99    /* Create child run */
    100    r = pthread_create(&child, &attr, child_func, NULL);
    101    assert(r == 0);
    102    r = pthread_join(child, NULL);
    103    assert(r == 0);
    104 
    105    /* Remove file */
    106    unlink(file_name);
    107    return 0;
    108 }
    109 
    110