Contributed by Kalevi Suominen <kalevi.suominen@helsinki.fi>.
[libsigsegv/ericb.git] / src / handler-unix.c
blob6e5bd45446a6753d2bf2c9d94ba30fb9f910e55b
1 /* Fault handler information. Unix version.
2 Copyright (C) 1993-1999, 2002-2003 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)
7 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 #include "sigsegv.h"
20 /* On the average Unix platform, we define
22 HAVE_SIGSEGV_RECOVERY
23 if there is a fault-*.h include file which defines
24 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
26 HAVE_STACK_OVERFLOW_RECOVERY
27 if HAVE_SIGALTSTACK is set and
28 at least two of the following are true:
29 A) There is a fault-*.h include file which defines
30 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
31 B) There is a fault-*.h include file which defines
32 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_STACKPOINTER.
33 C) There is a stackvma-*.c, other than stackvma-none.c, which
34 defines sigsegv_get_vma.
36 Why? Obviously, to catch stack overflow, we need an alternate signal
37 stack; this requires kernel support. But we also need to distinguish
38 (with a reasonable confidence) a stack overflow from a regular SIGSEGV.
39 If we have A) and B), we use the
40 Heuristic AB: If the fault address is near the stack pointer, it's a
41 stack overflow.
42 If we have A) and C), we use the
43 Heuristic AC: If the fault address is near and beyond the bottom of
44 the stack's virtual memory area, it's a stack overflow.
45 If we have B) and C), we use the
46 Heuristic BC: If the stack pointer is near the bottom of the stack's
47 virtual memory area, it's a stack overflow.
48 This heuristic comes in two flavours: On OSes which let the stack's
49 VMA grow continuously, we determine the bottom by use of getrlimit().
50 On OSes which preallocate the stack's VMA with its maximum size
51 (like BeOS), we use the stack's VMA directly.
54 #include <stddef.h> /* needed for NULL on SunOS4 */
55 #include <stdlib.h>
56 #include <signal.h>
57 #if HAVE_SYS_SIGNAL_H
58 # include <sys/signal.h>
59 #endif
60 #include <errno.h>
62 /* For MacOSX. */
63 #ifndef SS_DISABLE
64 #define SS_DISABLE SA_DISABLE
65 #endif
67 #include "fault.h"
68 #include CFG_SIGNALS
70 #if HAVE_STACK_OVERFLOW_RECOVERY
72 #include <stdio.h> /* perror */
74 #if HAVE_GETRLIMIT
75 # include <sys/types.h>
76 # include <sys/time.h>
77 # include <sys/resource.h> /* declares struct rlimit */
78 #endif
80 /* Platform dependent:
81 Determine the virtual memory area of a given address. */
82 #include "stackvma.h"
84 /* Platform dependent:
85 Leaving a signal handler executing on the alternate stack. */
86 #include "leave.h"
88 #if HAVE_STACKVMA
90 /* Address of the last byte belonging to the stack vma. */
91 static unsigned long stack_top = 0;
93 /* Needs to be called once only. */
94 static void
95 remember_stack_top (void *some_variable_on_stack)
97 struct vma_struct vma;
99 if (sigsegv_get_vma ((unsigned long) some_variable_on_stack, &vma) >= 0)
100 stack_top = vma.end - 1;
103 #endif /* HAVE_STACKVMA */
105 static stackoverflow_handler_t stk_user_handler = (stackoverflow_handler_t)NULL;
106 static unsigned long stk_extra_stack;
107 static unsigned long stk_extra_stack_size;
109 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
111 #if HAVE_SIGSEGV_RECOVERY
113 /* User's SIGSEGV handler. */
114 static sigsegv_handler_t user_handler = (sigsegv_handler_t)NULL;
116 #endif /* HAVE_SIGSEGV_RECOVERY */
119 /* Our SIGSEGV handler, with OS dependent argument list. */
121 #if HAVE_SIGSEGV_RECOVERY
123 static void
124 sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
126 void *address = (void *) (SIGSEGV_FAULT_ADDRESS);
128 #if HAVE_STACK_OVERFLOW_RECOVERY
129 #if !(HAVE_STACKVMA || defined SIGSEGV_FAULT_STACKPOINTER)
130 #error "Insufficient heuristics for detecting a stack overflow. Either define CFG_STACKVMA and HAVE_STACKVMA correctly, or define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!"
131 #endif
133 /* Call user's handler. */
134 if (user_handler && (*user_handler) (address, 0))
136 /* Handler successful. */
138 else
140 /* Handler declined responsibility. */
142 /* Did the user install a stack overflow handler? */
143 if (stk_user_handler)
145 /* See whether it was a stack overflow. If so, longjump away. */
146 #ifdef SIGSEGV_FAULT_STACKPOINTER
147 unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
148 #ifdef __ia64
149 unsigned long old_bsp = (unsigned long) (SIGSEGV_FAULT_BSP_POINTER);
150 #endif
151 #endif
153 #if HAVE_STACKVMA
154 /* Were we able to determine the stack top? */
155 if (stack_top)
157 /* Determine stack bounds. */
158 struct vma_struct vma;
160 if (sigsegv_get_vma (stack_top, &vma) >= 0)
162 /* Heuristic AC: If the fault_address is nearer to the stack
163 segment's [start,end] than to the previous segment, we
164 consider it a stack overflow.
165 In the case of IA-64, we know that the previous segment
166 is the up-growing bsp segment, and either of the two
167 stacks can overflow. */
168 unsigned long addr = (unsigned long) address;
170 #ifdef __ia64
171 if (addr >= vma.prev_end && addr <= vma.end - 1)
172 #else
173 #if STACK_DIRECTION < 0
174 if (addr >= vma.start
175 ? (addr <= vma.end - 1)
176 : vma.is_near_this (addr, &vma))
177 #else
178 if (addr <= vma.end - 1
179 ? (addr >= vma.start)
180 : vma.is_near_this (addr, &vma))
181 #endif
182 #endif
183 #else
184 /* Heuristic AB: If the fault address is near the stack pointer,
185 it's a stack overflow. */
186 unsigned long addr = (unsigned long) address;
188 if ((addr <= old_sp + 4096 && old_sp <= addr + 4096)
189 #ifdef __ia64
190 || (addr <= old_bsp + 4096 && old_bsp <= addr + 4096)
191 #endif
195 #endif
197 #ifdef SIGSEGV_FAULT_STACKPOINTER
198 int emergency =
199 (old_sp >= stk_extra_stack
200 && old_sp <= stk_extra_stack + stk_extra_stack_size);
201 stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
202 #else
203 int emergency = 0;
204 stackoverflow_context_t context = (void *) 0;
205 #endif
206 /* Call user's handler. */
207 (*stk_user_handler) (emergency, context);
212 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
214 if (user_handler && (*user_handler) (address, 1))
216 /* Handler successful. */
218 else
220 /* Handler declined responsibility for real. */
222 /* Remove ourselves and dump core. */
223 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
226 #if HAVE_STACK_OVERFLOW_RECOVERY
228 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
231 #elif HAVE_STACK_OVERFLOW_RECOVERY
233 static void
234 #ifdef SIGSEGV_FAULT_STACKPOINTER
235 sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
236 #else
237 sigsegv_handler (int sig)
238 #endif
240 #if !((HAVE_GETRLIMIT && defined RLIMIT_STACK) || defined SIGSEGV_FAULT_STACKPOINTER)
241 #error "Insufficient heuristics for detecting a stack overflow. Either define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!"
242 #endif
244 /* Did the user install a handler? */
245 if (stk_user_handler)
247 /* See whether it was a stack overflow. If so, longjump away. */
248 #ifdef SIGSEGV_FAULT_STACKPOINTER
249 unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
250 #endif
252 /* Were we able to determine the stack top? */
253 if (stack_top)
255 /* Determine stack bounds. */
256 struct vma_struct vma;
258 if (sigsegv_get_vma (stack_top, &vma) >= 0)
260 #if HAVE_GETRLIMIT && defined RLIMIT_STACK
261 /* Heuristic BC: If the stack size has reached its maximal size,
262 and old_sp is near the low end, we consider it a stack
263 overflow. */
264 struct rlimit rl;
266 if (getrlimit (RLIMIT_STACK, &rl) >= 0)
268 unsigned long current_stack_size = vma.end - vma.start;
269 unsigned long max_stack_size = rl.rlim_cur;
270 if (current_stack_size <= max_stack_size + 4096
271 && max_stack_size <= current_stack_size + 4096
272 #else
274 if (1
275 #endif
276 #ifdef SIGSEGV_FAULT_STACKPOINTER
277 /* Heuristic BC: If we know old_sp, and it is neither
278 near the low end, nor in the alternate stack, then
279 it's probably not a stack overflow. */
280 && ((old_sp >= stk_extra_stack
281 && old_sp <= stk_extra_stack + stk_extra_stack_size)
282 #if STACK_DIRECTION < 0
283 || (old_sp <= vma.start + 4096
284 && vma.start <= old_sp + 4096))
285 #else
286 || (old_sp <= vma.end + 4096
287 && vma.end <= old_sp + 4096))
288 #endif
289 #endif
292 #ifdef SIGSEGV_FAULT_STACKPOINTER
293 int emergency =
294 (old_sp >= stk_extra_stack
295 && old_sp <= stk_extra_stack + stk_extra_stack_size);
296 stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
297 #else
298 int emergency = 0;
299 stackoverflow_context_t context = (void *) 0;
300 #endif
301 /* Call user's handler. */
302 (*stk_user_handler)(emergency,context);
309 /* Remove ourselves and dump core. */
310 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
313 #endif
316 static void
317 install_for (int sig)
319 struct sigaction action;
321 #ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
322 action.sa_sigaction = &sigsegv_handler;
323 #else
324 action.sa_handler = (void (*) (int)) &sigsegv_handler;
325 #endif
326 /* Block most signals while SIGSEGV is being handled. */
327 /* Signals SIGKILL, SIGSTOP cannot be blocked. */
328 /* Signals SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU are not blocked because
329 dealing with these signals seems dangerous. */
330 /* Signals SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTRAP, SIGIOT, SIGEMT, SIGBUS,
331 SIGSYS, SIGSTKFLT are not blocked because these are synchronous signals,
332 which may require immediate intervention, otherwise the process may
333 starve. */
334 sigemptyset (&action.sa_mask);
335 #ifdef SIGHUP
336 sigaddset (&action.sa_mask,SIGHUP);
337 #endif
338 #ifdef SIGINT
339 sigaddset (&action.sa_mask,SIGINT);
340 #endif
341 #ifdef SIGQUIT
342 sigaddset (&action.sa_mask,SIGQUIT);
343 #endif
344 #ifdef SIGPIPE
345 sigaddset (&action.sa_mask,SIGPIPE);
346 #endif
347 #ifdef SIGALRM
348 sigaddset (&action.sa_mask,SIGALRM);
349 #endif
350 #ifdef SIGTERM
351 sigaddset (&action.sa_mask,SIGTERM);
352 #endif
353 #ifdef SIGUSR1
354 sigaddset (&action.sa_mask,SIGUSR1);
355 #endif
356 #ifdef SIGUSR2
357 sigaddset (&action.sa_mask,SIGUSR2);
358 #endif
359 #ifdef SIGCHLD
360 sigaddset (&action.sa_mask,SIGCHLD);
361 #endif
362 #ifdef SIGCLD
363 sigaddset (&action.sa_mask,SIGCLD);
364 #endif
365 #ifdef SIGURG
366 sigaddset (&action.sa_mask,SIGURG);
367 #endif
368 #ifdef SIGIO
369 sigaddset (&action.sa_mask,SIGIO);
370 #endif
371 #ifdef SIGPOLL
372 sigaddset (&action.sa_mask,SIGPOLL);
373 #endif
374 #ifdef SIGXCPU
375 sigaddset (&action.sa_mask,SIGXCPU);
376 #endif
377 #ifdef SIGXFSZ
378 sigaddset (&action.sa_mask,SIGXFSZ);
379 #endif
380 #ifdef SIGVTALRM
381 sigaddset (&action.sa_mask,SIGVTALRM);
382 #endif
383 #ifdef SIGPROF
384 sigaddset (&action.sa_mask,SIGPROF);
385 #endif
386 #ifdef SIGPWR
387 sigaddset (&action.sa_mask,SIGPWR);
388 #endif
389 #ifdef SIGLOST
390 sigaddset (&action.sa_mask,SIGLOST);
391 #endif
392 #ifdef SIGWINCH
393 sigaddset (&action.sa_mask,SIGWINCH);
394 #endif
395 /* Note that sigaction() implicitly adds sig itself to action.sa_mask. */
396 /* Ask the OS to provide a structure siginfo_t to the handler. */
397 #ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
398 action.sa_flags = SA_SIGINFO;
399 #else
400 action.sa_flags = 0;
401 #endif
402 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGALTSTACK /* not BeOS */
403 /* Work around Linux 2.2.5 bug: If SA_ONSTACK is specified but sigaltstack()
404 has not been called, the kernel will busy loop, eating CPU time. So
405 avoid setting SA_ONSTACK until the user has requested stack overflow
406 handling. */
407 if (stk_user_handler)
408 action.sa_flags |= SA_ONSTACK;
409 #endif
410 sigaction (sig, &action, (struct sigaction *) NULL);
414 sigsegv_install_handler (sigsegv_handler_t handler)
416 #if HAVE_SIGSEGV_RECOVERY
417 user_handler = handler;
419 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
421 return 0;
422 #else
423 return -1;
424 #endif
427 void
428 sigsegv_deinstall_handler (void)
430 #if HAVE_SIGSEGV_RECOVERY
431 user_handler = (sigsegv_handler_t)NULL;
433 #if HAVE_STACK_OVERFLOW_RECOVERY
434 if (!stk_user_handler)
435 #endif
437 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
439 #endif
442 void
443 sigsegv_leave_handler (void)
445 #if HAVE_STACK_OVERFLOW_RECOVERY
447 * Reset the system's knowledge that we are executing on the alternate
448 * stack. If we didn't do that, siglongjmp would be needed instead of
449 * longjmp to leave the signal handler.
451 sigsegv_reset_onstack_flag ();
452 #endif
456 stackoverflow_install_handler (stackoverflow_handler_t handler,
457 void *extra_stack, unsigned long extra_stack_size)
459 #if HAVE_STACK_OVERFLOW_RECOVERY
460 #if HAVE_STACKVMA
461 if (!stack_top)
463 int dummy;
464 remember_stack_top (&dummy);
465 if (!stack_top)
466 return -1;
468 #endif
470 stk_user_handler = handler;
471 stk_extra_stack = (unsigned long) extra_stack;
472 stk_extra_stack_size = extra_stack_size;
473 #ifdef __BEOS__
474 set_signal_stack (extra_stack, extra_stack_size);
475 #else /* HAVE_SIGALTSTACK */
477 stack_t ss;
478 ss.ss_sp = extra_stack;
479 ss.ss_size = extra_stack_size;
480 ss.ss_flags = 0; /* no SS_DISABLE */
481 if (sigaltstack (&ss, (stack_t*)0) < 0)
482 return -1;
484 #endif
486 /* Install the signal handlers with SA_ONSTACK. */
487 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
488 return 0;
489 #else
490 return -1;
491 #endif
494 void
495 stackoverflow_deinstall_handler (void)
497 #if HAVE_STACK_OVERFLOW_RECOVERY
498 stk_user_handler = (stackoverflow_handler_t) NULL;
500 #if HAVE_SIGSEGV_RECOVERY
501 if (user_handler)
503 /* Reinstall the signal handlers without SA_ONSTACK, to avoid Linux
504 bug. */
505 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
507 else
508 #endif
510 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
513 #ifdef __BEOS__
514 /* We cannot undo the effect of set_signal_stack. */
515 fprintf (stderr, "libsigsegv (stackoverflow_deinstall_handler): not supported on this platform\n");
516 #else /* HAVE_SIGALTSTACK */
518 stack_t ss;
519 ss.ss_flags = SS_DISABLE;
520 if (sigaltstack (&ss, (stack_t *) 0) < 0)
521 perror ("libsigsegv (stackoverflow_deinstall_handler)");
523 #endif
525 #endif