1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2003 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm (at) 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 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 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 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 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 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 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