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  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