1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
2 Copyright (C) 2002-2021 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/>. */
27 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
29 # if defined _WIN32 && !defined __CYGWIN__
30 /* Windows doesn't have sigset_t. */
32 # define sigemptyset(set)
33 # define sigprocmask(how,set,oldset)
36 # include "mmap-anon-util.h"
37 # include <stddef.h> /* needed for NULL on SunOS4 */
38 # include <stdlib.h> /* for abort, exit */
42 # include <sys/types.h>
43 # include <sys/time.h>
44 # include <sys/resource.h>
46 # include "altstack-util.h"
51 volatile int pass = 0;
55 stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3)
57 int arg = (int) (long) arg1;
58 longjmp (mainloop, arg);
62 stackoverflow_handler (int emergency, stackoverflow_context_t scp)
66 printf ("Stack overflow %d caught.\n", pass);
69 printf ("Segmentation violation misdetected as stack overflow.\n");
72 sigprocmask (SIG_SETMASK, &mainsigset, NULL);
73 sigsegv_leave_handler (stackoverflow_handler_continuation,
74 (void *) (long) (emergency ? -1 : pass), NULL, NULL);
78 sigsegv_handler (void *address, int emergency)
80 /* This test is necessary to distinguish stack overflow and SIGSEGV. */
87 printf ("Stack overflow %d missed.\n", pass);
91 printf ("Segmentation violation correctly detected.\n");
92 sigprocmask (SIG_SETMASK, &mainsigset, NULL);
93 return sigsegv_leave_handler (stackoverflow_handler_continuation,
94 (void *) (long) pass, NULL, NULL);
98 recurse_1 (int n, volatile int *p)
101 *recurse_1 (n + 1, p) += n;
106 recurse (volatile int n)
108 return *recurse_1 (n, &n);
118 # if HAVE_SETRLIMIT && defined RLIMIT_STACK
119 /* Before starting the endless recursion, try to be friendly to the user's
120 machine. On some Linux 2.2.x systems, there is no stack limit for user
121 processes at all. We don't want to kill such systems. */
123 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
124 setrlimit (RLIMIT_STACK, &rl);
127 /* Prepare the storage for the alternate stack. */
128 prepare_alternate_stack ();
130 /* Install the stack overflow handler. */
131 if (stackoverflow_install_handler (&stackoverflow_handler,
132 mystack, MYSTACK_SIZE)
137 # if !HAVE_MAP_ANONYMOUS
138 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
141 # if defined __linux__ && defined __sparc__
142 /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
143 PROT_READ | PROT_WRITE. */
144 prot_unwritable = PROT_NONE;
146 prot_unwritable = PROT_READ;
149 /* Setup some mmaped memory. */
150 p = mmap_zeromap ((void *) 0x12340000, 0x4000);
151 if (p == (void *)(-1))
153 fprintf (stderr, "mmap_zeromap failed.\n");
156 page = (uintptr_t) p;
158 /* Make it read-only. */
159 if (mprotect ((void *) page, 0x4000, prot_unwritable) < 0)
161 fprintf (stderr, "mprotect failed.\n");
165 /* Install the SIGSEGV handler. */
166 if (sigsegv_install_handler (&sigsegv_handler) < 0)
169 /* Save the current signal mask. */
170 sigemptyset (&emptyset);
171 sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
173 /* Provoke two stack overflows in a row. */
174 switch (setjmp (mainloop))
177 printf ("emergency exit\n"); exit (1);
179 printf ("Starting recursion pass %d.\n", pass + 1);
181 printf ("no endless recursion?!\n"); exit (1);
183 *(volatile int *) (page + 0x678) = 42;
186 *(volatile int *) 0 = 42;
194 /* Validate that the alternate stack did not overflow. */
195 check_alternate_stack_no_overflow ();
197 printf ("Test passed.\n");