1 /* Test that stack overflow and SIGSEGV are correctly distinguished.
2 Copyright (C) 2002-2005 Bruno Haible <bruno@clisp.org>
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, or (at your option)
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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY
24 #if defined _WIN32 && !defined __CYGWIN__
25 /* Windows doesn't have sigset_t. */
27 # define sigemptyset(set)
28 # define sigprocmask(how,set,oldset)
35 #include <stddef.h> /* needed for NULL on SunOS4 */
36 #include <stdlib.h> /* for abort, exit */
40 # include <sys/types.h>
41 # include <sys/time.h>
42 # include <sys/resource.h>
48 volatile int pass
= 0;
52 stackoverflow_handler (int emergency
, stackoverflow_context_t scp
)
56 printf ("Stack overflow %d caught.\n", pass
);
59 printf ("Segmentation violation misdetected as stack overflow.\n");
62 sigprocmask (SIG_SETMASK
, &mainsigset
, NULL
);
63 sigsegv_leave_handler ();
64 longjmp (mainloop
, emergency
? -1 : pass
);
68 sigsegv_handler (void *address
, int emergency
)
70 /* This test is necessary to distinguish stack overflow and SIGSEGV. */
77 printf ("Stack overflow %d missed.\n", pass
);
81 printf ("Segmentation violation correctly detected.\n");
82 sigprocmask (SIG_SETMASK
, &mainsigset
, NULL
);
83 sigsegv_leave_handler ();
84 longjmp (mainloop
, pass
);
88 recurse_1 (int n
, volatile int *p
)
91 *recurse_1 (n
+ 1, p
) += n
;
96 recurse (volatile int n
)
98 return *recurse_1 (n
, (volatile int *) &n
);
108 #if HAVE_SETRLIMIT && defined RLIMIT_STACK
109 /* Before starting the endless recursion, try to be friendly to the user's
110 machine. On some Linux 2.2.x systems, there is no stack limit for user
111 processes at all. We don't want to kill such systems. */
113 rl
.rlim_cur
= rl
.rlim_max
= 0x100000; /* 1 MB */
114 setrlimit (RLIMIT_STACK
, &rl
);
117 /* Install the stack overflow handler. */
118 if (stackoverflow_install_handler (&stackoverflow_handler
,
119 mystack
, sizeof (mystack
))
124 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
125 zero_fd
= open ("/dev/zero", O_RDONLY
, 0644);
128 /* Setup some mmaped memory. */
129 p
= mmap_zeromap ((void *) 0x12340000, 0x4000);
130 if (p
== (void *)(-1))
132 fprintf (stderr
, "mmap_zeromap failed.\n");
135 page
= (unsigned long) p
;
137 /* Make it read-only. */
138 if (mprotect ((void *) page
, 0x4000, PROT_READ
) < 0)
140 fprintf (stderr
, "mprotect failed.\n");
144 /* Install the SIGSEGV handler. */
145 if (sigsegv_install_handler (&sigsegv_handler
) < 0)
148 /* Save the current signal mask. */
149 sigemptyset (&emptyset
);
150 sigprocmask (SIG_BLOCK
, &emptyset
, &mainsigset
);
152 /* Provoke two stack overflows in a row. */
153 switch (setjmp (mainloop
))
156 printf ("emergency exit\n"); exit (1);
158 printf ("Starting recursion pass %d.\n", pass
+ 1);
160 printf ("no endless recursion?!\n"); exit (1);
162 *(int *) (page
+ 0x678) = 42;
170 printf ("Test passed.\n");