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
raise_longjmp(jmp_buf jbuf,int i,int n)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
test_setjmp(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
raise_siglongjmp(sigjmp_buf jbuf,int i,int n)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
test_sigsetjmp(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
sighandler(int signal)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
main(int argc,char ** argv UNUSED)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 }
286