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
21static volatile char *lowest_j;
22static jmp_buf goback;
23
24static void sigsegv_handler(int signr)
25{
26   longjmp(goback, 1);
27}
28
29static 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
42static void say_something(void)
43{
44  fprintf(stderr, "plugh\n");
45}
46
47static 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
57int 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