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 
sigsegv_handler(int signr)24 static void sigsegv_handler(int signr)
25 {
26    longjmp(goback, 1);
27 }
28 
bad_things_till_guard_page(void)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 
say_something(void)42 static void say_something(void)
43 {
44   fprintf(stderr, "plugh\n");
45 }
46 
child_func(void * arg)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 
main(int argc,const char ** argv)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