nstrftime, c-nstrftime tests: Avoid test failures on native Windows.
[gnulib.git] / tests / test-sigsegv-catch-stackoverflow2.c
blob60f7eb0cfbcac43a6fb361b38e126f0150467ab8
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. */
19 #include <config.h>
21 /* Specification. */
22 #include "sigsegv.h"
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <limits.h>
28 /* Skip this test when an address sanitizer is in use. */
29 #ifndef __has_feature
30 # define __has_feature(a) 0
31 #endif
32 #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
33 # undef HAVE_STACK_OVERFLOW_RECOVERY
34 #endif
36 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
38 # if defined _WIN32 && !defined __CYGWIN__
39 /* Windows doesn't have sigset_t. */
40 typedef int sigset_t;
41 # define sigemptyset(set)
42 # define sigprocmask(how,set,oldset)
43 # endif
45 # include "mmap-anon-util.h"
46 # include <stddef.h> /* needed for NULL on SunOS4 */
47 # include <stdlib.h> /* for abort, exit */
48 # include <signal.h>
49 # include <setjmp.h>
50 # if HAVE_SETRLIMIT
51 # include <sys/types.h>
52 # include <sys/time.h>
53 # include <sys/resource.h>
54 # endif
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 */;
64 static void
65 stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3)
67 int arg = (int) (long) arg1;
68 longjmp (mainloop, arg);
71 static void
72 stackoverflow_handler (int emergency, stackoverflow_context_t scp)
74 pass++;
75 if (pass <= 2)
76 printf ("Stack overflow %d caught.\n", pass);
77 else
79 printf ("Segmentation violation misdetected as stack overflow.\n");
80 exit (1);
82 sigprocmask (SIG_SETMASK, &mainsigset, NULL);
83 sigsegv_leave_handler (stackoverflow_handler_continuation,
84 (void *) (long) (emergency ? -1 : pass), NULL, NULL);
87 static int
88 sigsegv_handler (void *address, int emergency)
90 /* This test is necessary to distinguish stack overflow and SIGSEGV. */
91 if (!emergency)
92 return 0;
94 pass++;
95 if (pass <= 2)
97 printf ("Stack overflow %d missed.\n", pass);
98 exit (1);
100 else
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)
110 if (n < INT_MAX)
111 *recurse_1 (n + 1, p) += n;
112 return p;
115 static int
116 recurse (volatile int n)
118 return *recurse_1 (n, &n);
122 main ()
124 int prot_unwritable;
125 void *p;
126 sigset_t emptyset;
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. */
132 struct rlimit rl;
133 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
134 setrlimit (RLIMIT_STACK, &rl);
135 # endif
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)
143 < 0)
144 exit (2);
146 /* Preparations. */
147 # if !HAVE_MAP_ANONYMOUS
148 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
149 # endif
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;
155 # else
156 prot_unwritable = PROT_READ;
157 # endif
159 /* Setup some mmapped memory. */
160 p = mmap_zeromap ((void *) 0x12340000, 0x4000);
161 if (p == (void *)(-1))
163 fprintf (stderr, "mmap_zeromap failed.\n");
164 exit (2);
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");
172 exit (2);
175 /* Install the SIGSEGV handler. */
176 if (sigsegv_install_handler (&sigsegv_handler) < 0)
177 exit (2);
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))
186 case -1:
187 printf ("emergency exit\n"); exit (1);
188 case 0: case 1:
189 printf ("Starting recursion pass %d.\n", pass + 1);
190 recurse (0);
191 printf ("no endless recursion?!\n"); exit (1);
192 case 2:
193 *(volatile int *) (page + 0x678) = 42;
194 break;
195 case 3:
196 *null_pointer_to_volatile_int = 42;
197 break;
198 case 4:
199 break;
200 default:
201 abort ();
204 /* Validate that the alternate stack did not overflow. */
205 check_alternate_stack_no_overflow ();
207 printf ("Test passed.\n");
208 exit (0);
211 #else
214 main ()
216 return 77;
219 #endif