1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc.
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 /* Written by Bruno Haible and Eric Blake. */
28 /* Skip this test when an address sanitizer is in use. */
30 # define __has_feature(a) 0
32 #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
33 # undef HAVE_STACK_OVERFLOW_RECOVERY
36 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
38 # if defined _WIN32 && !defined __CYGWIN__
39 /* Windows doesn't have sigset_t. */
41 # define sigemptyset(set)
42 # define sigprocmask(how,set,oldset)
45 # include "mmap-anon-util.h"
46 # include <stddef.h> /* needed for NULL on SunOS4 */
47 # include <stdlib.h> /* for abort, exit */
51 # include <sys/types.h>
52 # include <sys/time.h>
53 # include <sys/resource.h>
55 # include "altstack-util.h"
57 static jmp_buf mainloop
;
58 static sigset_t mainsigset
;
60 static volatile int pass
= 0;
61 static uintptr_t page
;
62 static volatile int *null_pointer_to_volatile_int
/* = NULL */;
65 stackoverflow_handler_continuation (void *arg1
, void *arg2
, void *arg3
)
67 int arg
= (int) (long) arg1
;
68 longjmp (mainloop
, arg
);
72 stackoverflow_handler (int emergency
, stackoverflow_context_t scp
)
76 printf ("Stack overflow %d caught.\n", pass
);
79 printf ("Segmentation violation misdetected as stack overflow.\n");
82 sigprocmask (SIG_SETMASK
, &mainsigset
, NULL
);
83 sigsegv_leave_handler (stackoverflow_handler_continuation
,
84 (void *) (long) (emergency
? -1 : pass
), NULL
, NULL
);
88 sigsegv_handler (void *address
, int emergency
)
90 /* This test is necessary to distinguish stack overflow and SIGSEGV. */
97 printf ("Stack overflow %d missed.\n", pass
);
101 printf ("Segmentation violation correctly detected.\n");
102 sigprocmask (SIG_SETMASK
, &mainsigset
, NULL
);
103 return sigsegv_leave_handler (stackoverflow_handler_continuation
,
104 (void *) (long) pass
, NULL
, NULL
);
107 static volatile int *
108 recurse_1 (int n
, volatile int *p
)
111 *recurse_1 (n
+ 1, p
) += n
;
116 recurse (volatile int n
)
118 return *recurse_1 (n
, &n
);
128 # if HAVE_SETRLIMIT && defined RLIMIT_STACK
129 /* Before starting the endless recursion, try to be friendly to the user's
130 machine. On some Linux 2.2.x systems, there is no stack limit for user
131 processes at all. We don't want to kill such systems. */
133 rl
.rlim_cur
= rl
.rlim_max
= 0x100000; /* 1 MB */
134 setrlimit (RLIMIT_STACK
, &rl
);
137 /* Prepare the storage for the alternate stack. */
138 prepare_alternate_stack ();
140 /* Install the stack overflow handler. */
141 if (stackoverflow_install_handler (&stackoverflow_handler
,
142 mystack
, MYSTACK_SIZE
)
147 # if !HAVE_MAP_ANONYMOUS
148 zero_fd
= open ("/dev/zero", O_RDONLY
, 0644);
151 # if defined __linux__ && defined __sparc__
152 /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
153 PROT_READ | PROT_WRITE. */
154 prot_unwritable
= PROT_NONE
;
156 prot_unwritable
= PROT_READ
;
159 /* Setup some mmapped memory. */
160 p
= mmap_zeromap ((void *) 0x12340000, 0x4000);
161 if (p
== (void *)(-1))
163 fprintf (stderr
, "mmap_zeromap failed.\n");
166 page
= (uintptr_t) p
;
168 /* Make it read-only. */
169 if (mprotect ((void *) page
, 0x4000, prot_unwritable
) < 0)
171 fprintf (stderr
, "mprotect failed.\n");
175 /* Install the SIGSEGV handler. */
176 if (sigsegv_install_handler (&sigsegv_handler
) < 0)
179 /* Save the current signal mask. */
180 sigemptyset (&emptyset
);
181 sigprocmask (SIG_BLOCK
, &emptyset
, &mainsigset
);
183 /* Provoke two stack overflows in a row. */
184 switch (setjmp (mainloop
))
187 printf ("emergency exit\n"); exit (1);
189 printf ("Starting recursion pass %d.\n", pass
+ 1);
191 printf ("no endless recursion?!\n"); exit (1);
193 *(volatile int *) (page
+ 0x678) = 42;
196 *null_pointer_to_volatile_int
= 42;
204 /* Validate that the alternate stack did not overflow. */
205 check_alternate_stack_no_overflow ();
207 printf ("Test passed.\n");