Add installation information for the tarball users and from a git checkout.
[libsigsegv.git] / tests / test-segv-dispatcher1.c
blobaa2963a252ae950cf2668901dc7f28e5102598a1
1 /* Test the dispatcher.
2 Copyright (C) 2002-2006, 2008, 2011, 2016, 2021, 2023 Bruno Haible <bruno@clisp.org>
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.
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.
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/>. */
17 #ifndef _MSC_VER
18 # include <config.h>
19 #endif
21 #include "sigsegv.h"
22 #include <stdint.h>
23 #include <stdio.h>
25 #if HAVE_SIGSEGV_RECOVERY
27 #include "mmap-anon-util.h"
28 #include <stdlib.h>
30 static sigsegv_dispatcher dispatcher;
32 static volatile unsigned int logcount = 0;
33 static volatile uintptr_t logdata[10];
35 /* Note about SIGSEGV_FAULT_ADDRESS_ALIGNMENT: It does not matter whether
36 fault_address is rounded off here because all intervals that we pass to
37 sigsegv_register are page-aligned. */
39 static int
40 area_handler (void *fault_address, void *user_arg)
42 uintptr_t area = *(uintptr_t *)user_arg;
43 logdata[logcount++] = area;
44 if (logcount >= sizeof (logdata) / sizeof (logdata[0]))
45 abort ();
46 if (!((uintptr_t)fault_address >= area
47 && (uintptr_t)fault_address - area < 0x4000))
48 abort ();
49 if (mprotect ((void *) area, 0x4000, PROT_READ_WRITE) == 0)
50 return 1;
51 return 0;
54 static int
55 handler (void *fault_address, int serious)
57 return sigsegv_dispatch (&dispatcher, fault_address);
60 static void
61 barrier ()
65 int
66 main ()
68 int prot_unwritable;
69 void *p;
70 uintptr_t area1;
71 uintptr_t area2;
72 uintptr_t area3;
74 /* Preparations. */
75 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
76 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
77 #endif
78 sigsegv_init (&dispatcher);
79 sigsegv_install_handler (&handler);
81 #if defined __linux__ && defined __sparc__
82 /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
83 PROT_READ | PROT_WRITE. */
84 prot_unwritable = PROT_NONE;
85 #else
86 prot_unwritable = PROT_READ;
87 #endif
89 /* Setup some mmapped memory. */
91 p = mmap_zeromap ((void *) 0x12340000, 0x4000);
92 if (p == (void *)(-1))
94 fprintf (stderr, "mmap_zeromap failed.\n");
95 exit (2);
97 area1 = (uintptr_t) p;
98 sigsegv_register (&dispatcher, (void *) area1, 0x4000, &area_handler, &area1);
99 if (mprotect ((void *) area1, 0x4000, PROT_NONE) < 0)
101 fprintf (stderr, "mprotect failed.\n");
102 exit (2);
105 p = mmap_zeromap ((void *) 0x0BEE0000, 0x4000);
106 if (p == (void *)(-1))
108 fprintf (stderr, "mmap_zeromap failed.\n");
109 exit (2);
111 area2 = (uintptr_t) p;
112 sigsegv_register (&dispatcher, (void *) area2, 0x4000, &area_handler, &area2);
113 if (mprotect ((void *) area2, 0x4000, prot_unwritable) < 0)
115 fprintf (stderr, "mprotect failed.\n");
116 exit (2);
118 if (mprotect ((void *) area2, 0x4000, PROT_READ_WRITE) < 0
119 || mprotect ((void *) area2, 0x4000, prot_unwritable) < 0)
121 fprintf (stderr, "mprotect failed.\n");
122 exit (2);
125 p = mmap_zeromap ((void *) 0x06990000, 0x4000);
126 if (p == (void *)(-1))
128 fprintf (stderr, "mmap_zeromap failed.\n");
129 exit (2);
131 area3 = (uintptr_t) p;
132 sigsegv_register (&dispatcher, (void *) area3, 0x4000, &area_handler, &area3);
133 mprotect ((void *) area3, 0x4000, prot_unwritable);
135 /* This access should call the handler. */
136 ((volatile int *)area2)[230] = 22;
137 /* This access should call the handler. */
138 ((volatile int *)area3)[412] = 33;
139 /* This access should not give a signal. */
140 ((volatile int *)area2)[135] = 22;
141 /* This access should call the handler. */
142 ((volatile int *)area1)[612] = 11;
144 barrier();
146 /* Check that the handler was called three times. */
147 if (logcount != 3)
148 exit (1);
149 if (!(logdata[0] == area2 && logdata[1] == area3 && logdata[2] == area1))
150 exit (1);
151 printf ("Test passed.\n");
152 return 0;
155 #else
158 main ()
160 return 77;
163 #endif