(root)/
grep-3.11/
gnulib-tests/
test-sigsegv-catch-segv1.c
       1  /* Test that the handler is called, with the right fault address.
       2     Copyright (C) 2002-2023 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.  */
      18  
      19  #include <config.h>
      20  
      21  /* Specification.  */
      22  #include "sigsegv.h"
      23  
      24  #include <stdint.h>
      25  #include <stdio.h>
      26  
      27  #if HAVE_SIGSEGV_RECOVERY
      28  
      29  # include "mmap-anon-util.h"
      30  # include <stdlib.h>
      31  
      32  # if SIGSEGV_FAULT_ADDRESS_ALIGNMENT > 1UL
      33  #  include <unistd.h>
      34  #  define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS (getpagesize () - 1)
      35  # else
      36  #  define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS 0
      37  # endif
      38  
      39  uintptr_t page;
      40  
      41  volatile int handler_called = 0;
      42  
      43  static int
      44  handler (void *fault_address, int serious)
      45  {
      46    handler_called++;
      47    if (handler_called > 10)
      48      abort ();
      49    if (fault_address
      50        != (void *)((page + 0x678) & ~SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS))
      51      abort ();
      52    if (mprotect ((void *) page, 0x4000, PROT_READ_WRITE) == 0)
      53      return 1;
      54    return 0;
      55  }
      56  
      57  static void
      58  crasher (uintptr_t p)
      59  {
      60    *(volatile int *) (p + 0x678) = 42;
      61  }
      62  
      63  int
      64  main ()
      65  {
      66    int prot_unwritable;
      67    void *p;
      68  
      69    /* Preparations.  */
      70  # if !HAVE_MAP_ANONYMOUS
      71    zero_fd = open ("/dev/zero", O_RDONLY, 0644);
      72  # endif
      73  
      74  # if defined __linux__ && defined __sparc__
      75    /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
      76       PROT_READ | PROT_WRITE.  */
      77    prot_unwritable = PROT_NONE;
      78  # else
      79    prot_unwritable = PROT_READ;
      80  # endif
      81  
      82    /* Setup some mmaped memory.  */
      83    p = mmap_zeromap ((void *) 0x12340000, 0x4000);
      84    if (p == (void *)(-1))
      85      {
      86        fprintf (stderr, "mmap_zeromap failed.\n");
      87        exit (2);
      88      }
      89    page = (uintptr_t) p;
      90  
      91    /* Make it read-only.  */
      92    if (mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
      93      {
      94        fprintf (stderr, "mprotect failed.\n");
      95        exit (2);
      96      }
      97    /* Test whether it's possible to make it read-write after it was read-only.
      98       This is not possible on Cygwin.  */
      99    if (mprotect ((void *) page, 0x4000, PROT_READ_WRITE) < 0
     100        || mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
     101      {
     102        fprintf (stderr, "mprotect failed.\n");
     103        exit (2);
     104      }
     105  
     106    /* Install the SIGSEGV handler.  */
     107    sigsegv_install_handler (&handler);
     108  
     109    /* The first write access should invoke the handler and then complete.  */
     110    crasher (page);
     111    /* The second write access should not invoke the handler.  */
     112    crasher (page);
     113  
     114    /* Check that the handler was called only once.  */
     115    if (handler_called != 1)
     116      exit (1);
     117    /* Test passed!  */
     118    printf ("Test passed.\n");
     119    return 0;
     120  }
     121  
     122  #else
     123  
     124  int
     125  main ()
     126  {
     127    return 77;
     128  }
     129  
     130  #endif