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