Imported Upstream version 1.1
[platform/upstream/libunwind.git] / tests / test-setjmp.c
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2003 Hewlett-Packard Co
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
23
24 /* The setjmp()/longjmp(), sigsetjmp()/siglongjmp().  */
25
26 #include "compiler.h"
27
28 #include <setjmp.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 int nerrors;
36 int verbose;
37
38 static jmp_buf jbuf;
39 static sigjmp_buf sigjbuf;
40 static sigset_t sigset4;
41
42 void
43 raise_longjmp (jmp_buf jbuf, int i, int n)
44 {
45   while (i < n)
46     raise_longjmp (jbuf, i + 1, n);
47
48   longjmp (jbuf, n);
49 }
50
51 void
52 test_setjmp (void)
53 {
54   volatile int i;
55   jmp_buf jbuf;
56   int ret;
57
58   for (i = 0; i < 10; ++i)
59     {
60       if ((ret = setjmp (jbuf)))
61         {
62           if (verbose)
63             printf ("%s: secondary setjmp () return, ret=%d\n",
64                     __FUNCTION__, ret);
65           if (ret != i + 1)
66             {
67               fprintf (stderr, "%s: setjmp() returned %d, expected %d\n",
68                        __FUNCTION__, ret, i + 1);
69               ++nerrors;
70             }
71           continue;
72         }
73       if (verbose)
74         printf ("%s.%d: done with setjmp(); calling children\n",
75                 __FUNCTION__, i + 1);
76
77       raise_longjmp (jbuf, 0, i + 1);
78
79       fprintf (stderr, "%s: raise_longjmp() returned unexpectedly\n",
80                __FUNCTION__);
81       ++nerrors;
82     }
83 }
84
85
86 void
87 raise_siglongjmp (sigjmp_buf jbuf, int i, int n)
88 {
89   while (i < n)
90     raise_siglongjmp (jbuf, i + 1, n);
91
92   siglongjmp (jbuf, n);
93 }
94
95 void
96 test_sigsetjmp (void)
97 {
98   sigjmp_buf jbuf;
99   volatile int i;
100   int ret;
101
102   for (i = 0; i < 10; ++i)
103     {
104       if ((ret = sigsetjmp (jbuf, 1)))
105         {
106           if (verbose)
107             printf ("%s: secondary sigsetjmp () return, ret=%d\n",
108                     __FUNCTION__, ret);
109           if (ret != i + 1)
110             {
111               fprintf (stderr, "%s: sigsetjmp() returned %d, expected %d\n",
112                        __FUNCTION__, ret, i + 1);
113               ++nerrors;
114             }
115           continue;
116         }
117       if (verbose)
118         printf ("%s.%d: done with sigsetjmp(); calling children\n",
119                 __FUNCTION__, i + 1);
120
121       raise_siglongjmp (jbuf, 0, i + 1);
122
123       fprintf (stderr, "%s: raise_siglongjmp() returned unexpectedly\n",
124                __FUNCTION__);
125       ++nerrors;
126     }
127 }
128
129 void
130 sighandler (int signal)
131 {
132   if (verbose)
133     printf ("%s: got signal %d\n", __FUNCTION__, signal);
134
135   sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset4);
136   if (verbose)
137     printf ("%s: back from sigprocmask\n", __FUNCTION__);
138
139   siglongjmp (sigjbuf, 1);
140   printf ("%s: siglongjmp() returned unexpectedly!\n", __FUNCTION__);
141 }
142
143 int
144 main (int argc, char **argv UNUSED)
145 {
146   volatile sigset_t sigset1, sigset2, sigset3;
147   volatile struct sigaction act;
148
149   if (argc > 1)
150     verbose = 1;
151
152   sigemptyset ((sigset_t *) &sigset1);
153   sigaddset ((sigset_t *) &sigset1, SIGUSR1);
154   sigemptyset ((sigset_t *) &sigset2);
155   sigaddset ((sigset_t *) &sigset2, SIGUSR2);
156
157   memset ((void *) &act, 0, sizeof (act));
158   act.sa_handler = sighandler;
159   sigaction (SIGTERM, (struct sigaction *) &act, NULL);
160
161   test_setjmp ();
162   test_sigsetjmp ();
163
164   /* _setjmp() MUST NOT change signal mask: */
165   sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
166   if (_setjmp (jbuf))
167     {
168       sigemptyset ((sigset_t *) &sigset3);
169       sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
170       if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
171                   sizeof (sigset_t)) != 0)
172         {
173           fprintf (stderr, "FAILURE: _longjmp() manipulated signal mask!\n");
174           ++nerrors;
175         }
176       else if (verbose)
177         printf ("OK: _longjmp() seems not to change signal mask\n");
178     }
179   else
180     {
181       sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
182       _longjmp (jbuf, 1);
183     }
184
185   /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
186   sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
187   if (sigsetjmp (sigjbuf, 1))
188     {
189       sigemptyset ((sigset_t *) &sigset3);
190       sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
191       if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
192                   sizeof (sigset_t)) != 0)
193         {
194           fprintf (stderr,
195                    "FAILURE: siglongjmp() didn't restore signal mask!\n");
196           ++nerrors;
197         }
198       else if (verbose)
199         printf ("OK: siglongjmp() restores signal mask when asked to\n");
200     }
201   else
202     {
203       sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
204       siglongjmp (sigjbuf, 1);
205     }
206
207   /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
208   sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
209   if (sigsetjmp (sigjbuf, 0))
210     {
211       sigemptyset ((sigset_t *) &sigset3);
212       sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
213       if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
214                   sizeof (sigset_t)) != 0)
215         {
216           fprintf (stderr,
217                    "FAILURE: siglongjmp() changed signal mask!\n");
218           ++nerrors;
219         }
220       else if (verbose)
221         printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
222     }
223   else
224     {
225       sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
226       siglongjmp (sigjbuf, 1);
227     }
228
229   /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
230   sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
231   if (sigsetjmp (sigjbuf, 1))
232     {
233       sigemptyset ((sigset_t *) &sigset3);
234       sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
235       if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
236                   sizeof (sigset_t)) != 0)
237         {
238           fprintf (stderr,
239                    "FAILURE: siglongjmp() didn't restore signal mask!\n");
240           ++nerrors;
241         }
242       else if (verbose)
243         printf ("OK: siglongjmp() restores signal mask when asked to\n");
244     }
245   else
246     {
247       sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
248       kill (getpid (), SIGTERM);
249       fprintf (stderr, "FAILURE: unexpected return from kill()\n");
250       ++nerrors;
251     }
252
253   /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
254   sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
255   if (sigsetjmp (sigjbuf, 0))
256     {
257       sigemptyset ((sigset_t *) &sigset3);
258       sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
259       if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset4,
260                   sizeof (sigset_t)) != 0)
261         {
262           fprintf (stderr,
263                    "FAILURE: siglongjmp() changed signal mask!\n");
264           ++nerrors;
265         }
266       else if (verbose)
267         printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
268     }
269   else
270     {
271       sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
272       kill (getpid (), SIGTERM);
273       fprintf (stderr, "FAILURE: unexpected return from kill()\n");
274       ++nerrors;
275     }
276
277   if (nerrors > 0)
278     {
279       fprintf (stderr, "FAILURE: detected %d failures\n", nerrors);
280       exit (-1);
281     }
282   if (verbose)
283     printf ("SUCCESS\n");
284   return 0;
285 }