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 memset (&sigset1, 0, sizeof (sigset1));
153 memset (&sigset2, 0, sizeof (sigset2));
154 memset (&sigset3, 0, sizeof (sigset3));
155
156 sigemptyset ((sigset_t *) &sigset1);
157 sigaddset ((sigset_t *) &sigset1, SIGUSR1);
158 sigemptyset ((sigset_t *) &sigset2);
159 sigaddset ((sigset_t *) &sigset2, SIGUSR2);
160
161 memset ((void *) &act, 0, sizeof (act));
162 act.sa_handler = sighandler;
163 sigaction (SIGTERM, (struct sigaction *) &act, NULL);
164
165 test_setjmp ();
166 test_sigsetjmp ();
167
168 /* _setjmp() MUST NOT change signal mask: */
169 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
170 if (_setjmp (jbuf))
171 {
172 sigemptyset ((sigset_t *) &sigset3);
173 sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
174 if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
175 sizeof (sigset_t)) != 0)
176 {
177 fprintf (stderr, "FAILURE: _longjmp() manipulated signal mask!\n");
178 ++nerrors;
179 }
180 else if (verbose)
181 printf ("OK: _longjmp() seems not to change signal mask\n");
182 }
183 else
184 {
185 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
186 _longjmp (jbuf, 1);
187 }
188
189 /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
190 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
191 if (sigsetjmp (sigjbuf, 1))
192 {
193 sigemptyset ((sigset_t *) &sigset3);
194 sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
195 if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
196 sizeof (sigset_t)) != 0)
197 {
198 fprintf (stderr,
199 "FAILURE: siglongjmp() didn't restore signal mask!\n");
200 ++nerrors;
201 }
202 else if (verbose)
203 printf ("OK: siglongjmp() restores signal mask when asked to\n");
204 }
205 else
206 {
207 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
208 siglongjmp (sigjbuf, 1);
209 }
210
211 /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
212 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
213 if (sigsetjmp (sigjbuf, 0))
214 {
215 sigemptyset ((sigset_t *) &sigset3);
216 sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
217 if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
218 sizeof (sigset_t)) != 0)
219 {
220 fprintf (stderr,
221 "FAILURE: siglongjmp() changed signal mask!\n");
222 ++nerrors;
223 }
224 else if (verbose)
225 printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
226 }
227 else
228 {
229 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
230 siglongjmp (sigjbuf, 1);
231 }
232
233 /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
234 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
235 if (sigsetjmp (sigjbuf, 1))
236 {
237 sigemptyset ((sigset_t *) &sigset3);
238 sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
239 if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
240 sizeof (sigset_t)) != 0)
241 {
242 fprintf (stderr,
243 "FAILURE: siglongjmp() didn't restore signal mask!\n");
244 ++nerrors;
245 }
246 else if (verbose)
247 printf ("OK: siglongjmp() restores signal mask when asked to\n");
248 }
249 else
250 {
251 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
252 kill (getpid (), SIGTERM);
253 fprintf (stderr, "FAILURE: unexpected return from kill()\n");
254 ++nerrors;
255 }
256
257 /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
258 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
259 if (sigsetjmp (sigjbuf, 0))
260 {
261 sigemptyset ((sigset_t *) &sigset3);
262 sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
263 if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset4,
264 sizeof (sigset_t)) != 0)
265 {
266 fprintf (stderr,
267 "FAILURE: siglongjmp() changed signal mask!\n");
268 ++nerrors;
269 }
270 else if (verbose)
271 printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
272 }
273 else
274 {
275 sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
276 kill (getpid (), SIGTERM);
277 fprintf (stderr, "FAILURE: unexpected return from kill()\n");
278 ++nerrors;
279 }
280
281 if (nerrors > 0)
282 {
283 fprintf (stderr, "FAILURE: detected %d failures\n", nerrors);
284 exit (-1);
285 }
286 if (verbose)
287 printf ("SUCCESS\n");
288 return 0;
289 }
290