root/maint/gnulib/tests/test-sigsegv-catch-stackoverflow2.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stackoverflow_handler_continuation
  2. stackoverflow_handler
  3. sigsegv_handler
  4. recurse_1
  5. recurse
  6. main
  7. main

   1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
   2    Copyright (C) 2002-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 2 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Bruno Haible and Eric Blake.  */
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include "sigsegv.h"
  23 
  24 #include <stdint.h>
  25 #include <stdio.h>
  26 #include <limits.h>
  27 
  28 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
  29 
  30 # if defined _WIN32 && !defined __CYGWIN__
  31   /* Windows doesn't have sigset_t.  */
  32   typedef int sigset_t;
  33 #  define sigemptyset(set)
  34 #  define sigprocmask(how,set,oldset)
  35 # endif
  36 
  37 # include "mmap-anon-util.h"
  38 # include <stddef.h> /* needed for NULL on SunOS4 */
  39 # include <stdlib.h> /* for abort, exit */
  40 # include <signal.h>
  41 # include <setjmp.h>
  42 # if HAVE_SETRLIMIT
  43 #  include <sys/types.h>
  44 #  include <sys/time.h>
  45 #  include <sys/resource.h>
  46 # endif
  47 # include "altstack-util.h"
  48 
  49 static jmp_buf mainloop;
  50 static sigset_t mainsigset;
  51 
  52 static volatile int pass = 0;
  53 static uintptr_t page;
  54 static volatile int *null_pointer_to_volatile_int /* = NULL */;
  55 
  56 static void
  57 stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59   int arg = (int) (long) arg1;
  60   longjmp (mainloop, arg);
  61 }
  62 
  63 static void
  64 stackoverflow_handler (int emergency, stackoverflow_context_t scp)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66   pass++;
  67   if (pass <= 2)
  68     printf ("Stack overflow %d caught.\n", pass);
  69   else
  70     {
  71       printf ("Segmentation violation misdetected as stack overflow.\n");
  72       exit (1);
  73     }
  74   sigprocmask (SIG_SETMASK, &mainsigset, NULL);
  75   sigsegv_leave_handler (stackoverflow_handler_continuation,
  76                          (void *) (long) (emergency ? -1 : pass), NULL, NULL);
  77 }
  78 
  79 static int
  80 sigsegv_handler (void *address, int emergency)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82   /* This test is necessary to distinguish stack overflow and SIGSEGV.  */
  83   if (!emergency)
  84     return 0;
  85 
  86   pass++;
  87   if (pass <= 2)
  88     {
  89       printf ("Stack overflow %d missed.\n", pass);
  90       exit (1);
  91     }
  92   else
  93     printf ("Segmentation violation correctly detected.\n");
  94   sigprocmask (SIG_SETMASK, &mainsigset, NULL);
  95   return sigsegv_leave_handler (stackoverflow_handler_continuation,
  96                                 (void *) (long) pass, NULL, NULL);
  97 }
  98 
  99 static volatile int *
 100 recurse_1 (int n, volatile int *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102   if (n < INT_MAX)
 103     *recurse_1 (n + 1, p) += n;
 104   return p;
 105 }
 106 
 107 static int
 108 recurse (volatile int n)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110   return *recurse_1 (n, &n);
 111 }
 112 
 113 int
 114 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   int prot_unwritable;
 117   void *p;
 118   sigset_t emptyset;
 119 
 120 # if HAVE_SETRLIMIT && defined RLIMIT_STACK
 121   /* Before starting the endless recursion, try to be friendly to the user's
 122      machine.  On some Linux 2.2.x systems, there is no stack limit for user
 123      processes at all.  We don't want to kill such systems.  */
 124   struct rlimit rl;
 125   rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
 126   setrlimit (RLIMIT_STACK, &rl);
 127 # endif
 128 
 129   /* Prepare the storage for the alternate stack.  */
 130   prepare_alternate_stack ();
 131 
 132   /* Install the stack overflow handler.  */
 133   if (stackoverflow_install_handler (&stackoverflow_handler,
 134                                      mystack, MYSTACK_SIZE)
 135       < 0)
 136     exit (2);
 137 
 138   /* Preparations.  */
 139 # if !HAVE_MAP_ANONYMOUS
 140   zero_fd = open ("/dev/zero", O_RDONLY, 0644);
 141 # endif
 142 
 143 # if defined __linux__ && defined __sparc__
 144   /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
 145      PROT_READ | PROT_WRITE.  */
 146   prot_unwritable = PROT_NONE;
 147 # else
 148   prot_unwritable = PROT_READ;
 149 # endif
 150 
 151   /* Setup some mmaped memory.  */
 152   p = mmap_zeromap ((void *) 0x12340000, 0x4000);
 153   if (p == (void *)(-1))
 154     {
 155       fprintf (stderr, "mmap_zeromap failed.\n");
 156       exit (2);
 157     }
 158   page = (uintptr_t) p;
 159 
 160   /* Make it read-only.  */
 161   if (mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
 162     {
 163       fprintf (stderr, "mprotect failed.\n");
 164       exit (2);
 165     }
 166 
 167   /* Install the SIGSEGV handler.  */
 168   if (sigsegv_install_handler (&sigsegv_handler) < 0)
 169     exit (2);
 170 
 171   /* Save the current signal mask.  */
 172   sigemptyset (&emptyset);
 173   sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
 174 
 175   /* Provoke two stack overflows in a row.  */
 176   switch (setjmp (mainloop))
 177     {
 178     case -1:
 179       printf ("emergency exit\n"); exit (1);
 180     case 0: case 1:
 181       printf ("Starting recursion pass %d.\n", pass + 1);
 182       recurse (0);
 183       printf ("no endless recursion?!\n"); exit (1);
 184     case 2:
 185       *(volatile int *) (page + 0x678) = 42;
 186       break;
 187     case 3:
 188       *null_pointer_to_volatile_int = 42;
 189       break;
 190     case 4:
 191       break;
 192     default:
 193       abort ();
 194     }
 195 
 196   /* Validate that the alternate stack did not overflow.  */
 197   check_alternate_stack_no_overflow ();
 198 
 199   printf ("Test passed.\n");
 200   exit (0);
 201 }
 202 
 203 #else
 204 
 205 int
 206 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 207 {
 208   return 77;
 209 }
 210 
 211 #endif

/* [previous][next][first][last][top][bottom][index][help] */