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
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be
14included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH 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
35int nerrors;
36int verbose;
37
38static jmp_buf jbuf;
39static sigjmp_buf sigjbuf;
40static sigset_t sigset4;
41
42void
43raise_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
51void
52test_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
86void
87raise_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
95void
96test_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
129void
130sighandler (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
143int
144main (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