Add installation information for the tarball users and from a git checkout.
[libsigsegv.git] / tests / test-catch-stackoverflow2.c
blob3b7b9623c46bfe06162323955cff9a13610549d3
1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
2 Copyright (C) 2002-2024 Bruno Haible <bruno@clisp.org>
3 Copyright (C) 2010 Eric Blake <eblake@redhat.com>
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.
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.
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/>. */
18 #ifndef _MSC_VER
19 # include <config.h>
20 #endif
22 #include "sigsegv.h"
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <limits.h>
27 /* Skip this test when an address sanitizer is in use. */
28 #ifndef __has_feature
29 # define __has_feature(a) 0
30 #endif
31 #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
32 # undef HAVE_STACK_OVERFLOW_RECOVERY
33 #endif
35 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
37 #if defined _WIN32 && !defined __CYGWIN__
38 /* Windows doesn't have sigset_t. */
39 typedef int sigset_t;
40 # define sigemptyset(set)
41 # define sigprocmask(how,set,oldset)
42 #endif
44 #include "mmap-anon-util.h"
45 #include <stddef.h> /* needed for NULL on SunOS4 */
46 #include <stdlib.h> /* for abort, exit */
47 #include <signal.h>
48 #include <setjmp.h>
49 #if HAVE_SETRLIMIT
50 # include <sys/types.h>
51 # include <sys/time.h>
52 # include <sys/resource.h>
53 #endif
54 #include "altstack-util.h"
56 static jmp_buf mainloop;
57 static sigset_t mainsigset;
59 static volatile int pass = 0;
60 static uintptr_t page;
61 static int *volatile null_pointer /* = NULL */;
63 static void
64 stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3)
66 int arg = (int) (long) arg1;
67 longjmp (mainloop, arg);
70 static void
71 stackoverflow_handler (int emergency, stackoverflow_context_t scp)
73 pass++;
74 if (pass <= 2)
75 printf ("Stack overflow %d caught.\n", pass);
76 else
78 printf ("Segmentation violation misdetected as stack overflow.\n");
79 exit (1);
81 sigprocmask (SIG_SETMASK, &mainsigset, NULL);
82 sigsegv_leave_handler (stackoverflow_handler_continuation,
83 (void *) (long) (emergency ? -1 : pass), NULL, NULL);
86 static int
87 sigsegv_handler (void *address, int emergency)
89 /* This test is necessary to distinguish stack overflow and SIGSEGV. */
90 if (!emergency)
91 return 0;
93 pass++;
94 if (pass <= 2)
96 printf ("Stack overflow %d missed.\n", pass);
97 exit (1);
99 else
100 printf ("Segmentation violation correctly detected.\n");
101 sigprocmask (SIG_SETMASK, &mainsigset, NULL);
102 return sigsegv_leave_handler (stackoverflow_handler_continuation,
103 (void *) (long) pass, NULL, NULL);
106 static volatile int *
107 recurse_1 (int n, volatile int *p)
109 if (n < INT_MAX)
110 *recurse_1 (n + 1, p) += n;
111 return p;
114 static int
115 recurse (volatile int n)
117 return *recurse_1 (n, &n);
121 main ()
123 int prot_unwritable;
124 void *p;
125 sigset_t emptyset;
127 #if HAVE_SETRLIMIT && defined RLIMIT_STACK
128 /* Before starting the endless recursion, try to be friendly to the user's
129 machine. On some Linux 2.2.x systems, there is no stack limit for user
130 processes at all. We don't want to kill such systems. */
131 struct rlimit rl;
132 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
133 setrlimit (RLIMIT_STACK, &rl);
134 #endif
136 /* Prepare the storage for the alternate stack. */
137 prepare_alternate_stack ();
139 /* Install the stack overflow handler. */
140 if (stackoverflow_install_handler (&stackoverflow_handler,
141 mystack, SIGSTKSZ)
142 < 0)
143 exit (2);
145 /* Preparations. */
146 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
147 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
148 #endif
150 #if defined __linux__ && defined __sparc__
151 /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
152 PROT_READ | PROT_WRITE. */
153 prot_unwritable = PROT_NONE;
154 #else
155 prot_unwritable = PROT_READ;
156 #endif
158 /* Setup some mmapped memory. */
159 p = mmap_zeromap ((void *) 0x12340000, 0x4000);
160 if (p == (void *)(-1))
162 fprintf (stderr, "mmap_zeromap failed.\n");
163 exit (2);
165 page = (uintptr_t) p;
167 /* Make it read-only. */
168 if (mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
170 fprintf (stderr, "mprotect failed.\n");
171 exit (2);
174 /* Install the SIGSEGV handler. */
175 if (sigsegv_install_handler (&sigsegv_handler) < 0)
176 exit (2);
178 /* Save the current signal mask. */
179 sigemptyset (&emptyset);
180 sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
182 /* Provoke two stack overflows in a row. */
183 switch (setjmp (mainloop))
185 case -1:
186 printf ("emergency exit\n"); exit (1);
187 case 0: case 1:
188 printf ("Starting recursion pass %d.\n", pass + 1);
189 recurse (0);
190 printf ("no endless recursion?!\n"); exit (1);
191 case 2:
192 *(volatile int *) (page + 0x678) = 42;
193 break;
194 case 3:
195 *null_pointer = 42;
196 break;
197 case 4:
198 break;
199 default:
200 abort ();
203 /* Validate that the alternate stack did not overflow. */
204 check_alternate_stack_no_overflow ();
206 printf ("Test passed.\n");
207 exit (0);
210 #else
213 main ()
215 return 77;
218 #endif