Avoid deadlock in malloc on backtrace (BZ #16159)
[platform/upstream/linaro-glibc.git] / debug / tst-longjmp_chk2.c
1 /* Verify longjmp fortify checking does not reject signal stacks.
2
3    Test case mostly written by Paolo Bonzini <pbonzini@redhat.com>.  */
4 #include <assert.h>
5 #include <setjmp.h>
6 #include <signal.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <sys/resource.h>
12
13
14 static jmp_buf mainloop;
15 static sigset_t mainsigset;
16 static int pass;
17
18
19 static void
20 stackoverflow_handler (int sig)
21 {
22   stack_t altstack;
23   /* Sanity check to keep test from looping forever (in case the longjmp
24      chk code is slightly broken).  */
25   pass++;
26   assert (pass < 5);
27   sigaltstack (NULL, &altstack);
28   /* Using printf is not really kosher in signal handlers but we know
29      it will work.  */
30   printf ("%*sin signal handler\n", pass, "");
31   if (altstack.ss_flags & SS_ONSTACK)
32     printf ("%*son alternate stack\n", pass, "");
33   siglongjmp (mainloop, pass);
34 }
35
36
37 static volatile int *
38 recurse_1 (int n, volatile int *p)
39 {
40   if (n >= 0)
41     *recurse_1 (n + 1, p) += n;
42   return p;
43 }
44
45
46 static int
47 recurse (int n)
48 {
49   int sum = 0;
50   return *recurse_1 (n, &sum);
51 }
52
53
54 static int
55 do_test (void)
56 {
57   char mystack[SIGSTKSZ];
58   stack_t altstack;
59   struct sigaction action;
60   sigset_t emptyset;
61   /* Before starting the endless recursion, try to be friendly to the user's
62      machine.  On some Linux 2.2.x systems, there is no stack limit for user
63      processes at all.  We don't want to kill such systems.  */
64   struct rlimit rl;
65   rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
66   setrlimit (RLIMIT_STACK, &rl);
67   /* Install the alternate stack.  */
68   altstack.ss_sp = mystack;
69   altstack.ss_size = sizeof (mystack);
70   altstack.ss_flags = 0; /* no SS_DISABLE */
71   if (sigaltstack (&altstack, NULL) < 0)
72     {
73       puts ("first sigaltstack failed");
74       return 0;
75     }
76   /* Install the SIGSEGV handler.  */
77   sigemptyset (&action.sa_mask);
78   action.sa_handler = &stackoverflow_handler;
79   action.sa_flags = SA_ONSTACK;
80   sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
81   sigaction (SIGBUS, &action, (struct sigaction *) NULL);
82
83   /* Save the current signal mask.  */
84   sigemptyset (&emptyset);
85   sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
86
87   /* Provoke two stack overflows in a row.  */
88   if (sigsetjmp (mainloop, 1) != 0)
89     {
90       assert (pass != 0);
91       printf ("%*sout of signal handler\n", pass, "");
92     }
93   else
94     assert (pass == 0);
95
96   sigaltstack (NULL, &altstack);
97   if (altstack.ss_flags & SS_ONSTACK)
98     printf ("%*son alternate stack\n", pass, "");
99   else
100     printf ("%*snot on alternate stack\n", pass, "");
101
102   if (pass < 2)
103     {
104       recurse (0);
105       puts ("recurse call returned");
106       return 2;
107     }
108
109   altstack.ss_flags |= SS_DISABLE;
110   if (sigaltstack (&altstack, NULL) == -1)
111     printf ("disabling alternate stack failed\n");
112   else
113     printf ("disabling alternate stack succeeded \n");
114
115   return 0;
116 }
117
118 #define TEST_FUNCTION do_test ()
119 #include "../test-skeleton.c"