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