(root)/
m4-1.4.19/
tests/
test-sigsegv-catch-segv2.c
       1  /* Test that the handler can be exited multiple times.
       2     Copyright (C) 2002-2021  Bruno Haible <bruno@clisp.org>
       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  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include "sigsegv.h"
      21  
      22  #include <stdint.h>
      23  #include <stdio.h>
      24  
      25  #if HAVE_SIGSEGV_RECOVERY
      26  
      27  # if defined _WIN32 && !defined __CYGWIN__
      28    /* Windows doesn't have sigset_t.  */
      29    typedef int sigset_t;
      30  #  define sigemptyset(set)
      31  #  define sigprocmask(how,set,oldset)
      32  # endif
      33  
      34  # include "mmap-anon-util.h"
      35  # include <stdlib.h> /* for abort, exit */
      36  # include <signal.h>
      37  # include <setjmp.h>
      38  
      39  # if SIGSEGV_FAULT_ADDRESS_ALIGNMENT > 1UL
      40  #  include <unistd.h>
      41  #  define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS (getpagesize () - 1)
      42  # else
      43  #  define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS 0
      44  # endif
      45  
      46  jmp_buf mainloop;
      47  sigset_t mainsigset;
      48  
      49  volatile int pass = 0;
      50  uintptr_t page;
      51  
      52  volatile int handler_called = 0;
      53  
      54  static void
      55  handler_continuation (void *arg1, void *arg2, void *arg3)
      56  {
      57    longjmp (mainloop, pass);
      58  }
      59  
      60  int
      61  handler (void *fault_address, int serious)
      62  {
      63    handler_called++;
      64    if (handler_called > 10)
      65      abort ();
      66    if (fault_address
      67        != (void *)((page + 0x678 + 8 * pass) & ~SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS))
      68      abort ();
      69    pass++;
      70    printf ("Fault %d caught.\n", pass);
      71    sigprocmask (SIG_SETMASK, &mainsigset, NULL);
      72    return sigsegv_leave_handler (handler_continuation, NULL, NULL, NULL);
      73  }
      74  
      75  void
      76  crasher (uintptr_t p)
      77  {
      78    *(volatile int *) (p + 0x678 + 8 * pass) = 42;
      79  }
      80  
      81  int
      82  main ()
      83  {
      84    int prot_unwritable;
      85    void *p;
      86    sigset_t emptyset;
      87  
      88    /* Preparations.  */
      89  # if !HAVE_MAP_ANONYMOUS
      90    zero_fd = open ("/dev/zero", O_RDONLY, 0644);
      91  # endif
      92  
      93  # if defined __linux__ && defined __sparc__
      94    /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
      95       PROT_READ | PROT_WRITE.  */
      96    prot_unwritable = PROT_NONE;
      97  # else
      98    prot_unwritable = PROT_READ;
      99  # endif
     100  
     101    /* Setup some mmaped memory.  */
     102    p = mmap_zeromap ((void *) 0x12340000, 0x4000);
     103    if (p == (void *)(-1))
     104      {
     105        fprintf (stderr, "mmap_zeromap failed.\n");
     106        exit (2);
     107      }
     108    page = (uintptr_t) p;
     109  
     110    /* Make it read-only.  */
     111    if (mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
     112      {
     113        fprintf (stderr, "mprotect failed.\n");
     114        exit (2);
     115      }
     116  
     117    /* Install the SIGSEGV handler.  */
     118    if (sigsegv_install_handler (&handler) < 0)
     119      exit (2);
     120  
     121    /* Save the current signal mask.  */
     122    sigemptyset (&emptyset);
     123    sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
     124  
     125    /* Provoke two SIGSEGVs in a row.  */
     126    switch (setjmp (mainloop))
     127      {
     128      case 0: case 1:
     129        printf ("Doing SIGSEGV pass %d.\n", pass + 1);
     130        crasher (page);
     131        printf ("no SIGSEGV?!\n"); exit (1);
     132      case 2:
     133        break;
     134      default:
     135        abort ();
     136      }
     137  
     138    /* Test passed!  */
     139    printf ("Test passed.\n");
     140    return 0;
     141  }
     142  
     143  #else
     144  
     145  int
     146  main ()
     147  {
     148    return 77;
     149  }
     150  
     151  #endif