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