Home | History | Annotate | Download | only in tests
      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