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