1 /* Test the stack overflow handler.
2 Copyright (C) 2002-2025 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. */
21 /* On GNU/Hurd, when compiling with -D_FORTIFY_SOURCE=2, avoid an error
22 "*** longjmp causes uninitialized stack frame ***: terminated".
23 Cf. <https://sourceware.org/bugzilla/show_bug.cgi?id=32522> */
25 # undef _FORTIFY_SOURCE
26 # undef __USE_FORTIFY_LEVEL
35 /* Skip this test when an address sanitizer is in use. */
37 # define __has_feature(a) 0
39 #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
40 # undef HAVE_STACK_OVERFLOW_RECOVERY
43 #if HAVE_STACK_OVERFLOW_RECOVERY
45 # if defined _WIN32 && !defined __CYGWIN__
46 /* Windows doesn't have sigset_t. */
48 # define sigemptyset(set)
49 # define sigprocmask(how,set,oldset)
52 # include <stddef.h> /* needed for NULL on SunOS4 */
53 # include <stdlib.h> /* for abort, exit */
57 # include <sys/types.h>
58 # include <sys/time.h>
59 # include <sys/resource.h>
61 # include "altstack-util.h"
63 static jmp_buf mainloop
;
64 static sigset_t mainsigset
;
66 static volatile int pass
= 0;
68 static volatile char *stack_lower_bound
;
69 static volatile char *stack_upper_bound
;
72 stackoverflow_handler_continuation (void *arg1
, void *arg2
, void *arg3
)
74 #if defined __NetBSD__ && defined __i386__
75 /* On NetBSD 10.0/i386, when built as part of a testdir-all (but not as part
76 of a testdir for just the module 'sigsegv'!) this program crashes. The
78 - The alternate stack is not aligned (which is intentional, see
79 altstack-util.h) and NetBSD does not align the stack pointer while
80 switching to the alternate stack.
81 - When %esp is not aligned, the dynamic linker crashes in function
82 _rtld_bind while resolving the symbol 'longjmp'.
83 We would around this by aligning the stack pointer, to a multiple of 8. */
85 __asm__
__volatile__ ("movl %1,%0" : "=r" (argp
) : "r" (&arg1
));
87 __asm__
__volatile__ ("movl %%esp,%0" : "=r" (sp
));
89 __asm__
__volatile__ ("movl %0,%%esp" : : "r" (sp
));
92 int arg
= (int) (long) arg1
;
94 longjmp (mainloop
, arg
);
98 stackoverflow_handler (int emergency
, stackoverflow_context_t scp
)
101 volatile char *addr
= &dummy
;
102 if (!(addr
>= stack_lower_bound
&& addr
<= stack_upper_bound
))
105 printf ("Stack overflow %d caught.\n", pass
);
106 sigprocmask (SIG_SETMASK
, &mainsigset
, NULL
);
107 sigsegv_leave_handler (stackoverflow_handler_continuation
,
108 (void *) (long) (emergency
? -1 : pass
), NULL
, NULL
);
111 static volatile int *
112 recurse_1 (int n
, volatile int *p
)
115 *recurse_1 (n
+ 1, p
) += n
;
120 recurse (volatile int n
)
122 return *recurse_1 (n
, &n
);
130 # if HAVE_SETRLIMIT && defined RLIMIT_STACK
131 /* Before starting the endless recursion, try to be friendly to the user's
132 machine. On some Linux 2.2.x systems, there is no stack limit for user
133 processes at all. We don't want to kill such systems. */
135 rl
.rlim_cur
= rl
.rlim_max
= 0x100000; /* 1 MB */
136 setrlimit (RLIMIT_STACK
, &rl
);
139 /* Prepare the storage for the alternate stack. */
140 prepare_alternate_stack ();
142 /* Install the stack overflow handler. */
143 if (stackoverflow_install_handler (&stackoverflow_handler
,
144 mystack
, MYSTACK_SIZE
)
147 stack_lower_bound
= mystack
;
148 stack_upper_bound
= mystack
+ MYSTACK_SIZE
- 1;
150 /* Save the current signal mask. */
151 sigemptyset (&emptyset
);
152 sigprocmask (SIG_BLOCK
, &emptyset
, &mainsigset
);
154 /* Provoke two stack overflows in a row. */
155 switch (setjmp (mainloop
))
158 printf ("emergency exit\n"); exit (1);
160 printf ("Starting recursion pass %d.\n", pass
+ 1);
162 printf ("no endless recursion?!\n"); exit (1);
169 /* Validate that the alternate stack did not overflow. */
170 check_alternate_stack_no_overflow ();
172 printf ("Test passed.\n");