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