Detection du debordement de pile C

git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@3621 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
master
Xavier Leroy 2001-08-08 08:30:26 +00:00
parent fbe4ff190f
commit bf110cd0e2
5 changed files with 220 additions and 19 deletions

View File

@ -32,7 +32,7 @@ typedef value caml_generated_constant[1];
extern caml_generated_constant Out_of_memory, Sys_error, Failure,
Invalid_argument, End_of_file, Division_by_zero, Not_found,
Match_failure, Sys_blocked_io;
Match_failure, Sys_blocked_io, Stack_overflow;
/* Exception raising */
@ -99,12 +99,13 @@ void invalid_argument (char *msg)
because it allocates and we're out of memory...
We therefore build the bucket by hand.
This works OK because the exception value for Out_of_memory is also
statically allocated out of the heap. */
statically allocated out of the heap.
The same applies to Stack_overflow. */
static struct {
header_t hdr;
value exn;
} out_of_memory_bucket;
} out_of_memory_bucket, stack_overflow_bucket;
void raise_out_of_memory(void)
{
@ -113,6 +114,13 @@ void raise_out_of_memory(void)
mlraise((value) &(out_of_memory_bucket.exn));
}
void raise_stack_overflow(void)
{
stack_overflow_bucket.hdr = Make_header(1, 0, Caml_white);
stack_overflow_bucket.exn = (value) Stack_overflow;
mlraise((value) &(stack_overflow_bucket.exn));
}
void raise_sys_error(value msg)
{
raise_with_arg((value) Sys_error, msg);

View File

@ -27,6 +27,9 @@
#include "signals.h"
#include "stack.h"
#include "sys.h"
#ifdef HAS_STACK_OVERFLOW_DETECTION
#include <sys/resource.h>
#endif
#if defined(TARGET_power) && defined(SYS_rhapsody)
/* Confer machdep/ppc/unix_signal.c and mach/ppc/thread_status.h
@ -433,34 +436,126 @@ static void trap_handler(int sig, int code, struct sigcontext * context)
}
#endif
/* Machine- and OS-dependent handling of stack overflow */
#ifdef HAS_STACK_OVERFLOW_DETECTION
static char * system_stack_top;
static char sig_alt_stack[SIGSTKSZ];
static int is_stack_overflow(char * fault_addr, unsigned long in_c_code)
{
struct rlimit limit;
struct sigaction act;
/* Sanity checks:
- faulting address is word-aligned
- faulting address is within the stack
- we are not inside C code */
if (in_c_code == 0 &&
((long) fault_addr & (sizeof(long) - 1)) == 0 &&
getrlimit(RLIMIT_STACK, &limit) == 0 &&
fault_addr < system_stack_top &&
fault_addr >= system_stack_top - limit.rlim_cur - 0x2000) {
/* OK, caller can turn this into a Stack_overflow exception */
return 1;
} else {
/* Otherwise, deactivate our exception handler. Caller will
return, causing fatal signal to be generated at point of error. */
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGSEGV, &act, NULL);
return 0;
}
}
#if defined(TARGET_i386) && defined(SYS_linux_elf)
static void segv_handler(int signo, struct sigcontext sc)
{
if (is_stack_overflow((char *) sc.cr2, 0))
raise_stack_overflow();
}
#endif
#if defined(TARGET_i386) && !defined(SYS_linux_elf)
static void segv_handler(int signo, siginfo_t * info, void * arg)
{
if (is_stack_overflow((char *) info->si_addr, 0))
raise_stack_overflow();
}
#endif
#if defined(TARGET_alpha) && defined(SYS_digital)
static void segv_handler(int signo, siginfo_t * info, void * arg)
{
ucontext_t * context = (ucontext_t *) arg;
if (is_stack_overflow((char *) info->si_addr, caml_last_return_address)) {
/* Recover young_ptr and caml_exception_pointer from regs $13 and $15 */
young_ptr = (char *) (context->uc_mcontext.sc_regs[13]);
caml_exception_pointer = (char *) (context->uc_mcontext.sc_regs[15]);
raise_stack_overflow();
}
}
#endif
#endif
/* Initialization of signal stuff */
void init_signals(void)
{
/* Bound-check trap handling */
#if defined(TARGET_sparc) && \
(defined(SYS_sunos) || defined(SYS_bsd) || defined(SYS_linux))
struct sigaction act;
act.sa_handler = (void (*)(int)) trap_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGILL, &act, NULL);
{
struct sigaction act;
act.sa_handler = (void (*)(int)) trap_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGILL, &act, NULL);
}
#endif
#if defined(TARGET_sparc) && defined(SYS_solaris)
struct sigaction act;
act.sa_sigaction = trap_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_NODEFER;
sigaction(SIGILL, &act, NULL);
{
struct sigaction act;
act.sa_sigaction = trap_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_NODEFER;
sigaction(SIGILL, &act, NULL);
}
#endif
#if defined(TARGET_power)
struct sigaction act;
act.sa_handler = (void (*)(int)) trap_handler;
sigemptyset(&act.sa_mask);
{
struct sigaction act;
act.sa_handler = (void (*)(int)) trap_handler;
sigemptyset(&act.sa_mask);
#if defined(SYS_rhapsody) || defined(SYS_aix)
act.sa_flags = 0;
act.sa_flags = 0;
#else
act.sa_flags = SA_NODEFER;
act.sa_flags = SA_NODEFER;
#endif
sigaction(SIGTRAP, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
}
#endif
/* Stack overflow handling */
#ifdef HAS_STACK_OVERFLOW_DETECTION
{
struct sigaltstack stk;
struct sigaction act;
stk.ss_sp = sig_alt_stack;
stk.ss_size = SIGSTKSZ;
stk.ss_flags = 0;
#if defined(TARGET_i386) && defined(SYS_linux_elf)
act.sa_handler = (void (*)(int)) segv_handler;
act.sa_flags = SA_ONSTACK | SA_NODEFER;
#else
act.sa_sigaction = segv_handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
#endif
sigemptyset(&act.sa_mask);
system_stack_top = (char *) &act;
if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }
}
#endif
}

69
config/auto-aux/stackov.c Normal file
View File

@ -0,0 +1,69 @@
/***********************************************************************/
/* */
/* Objective Caml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 2001 Institut National de Recherche en Informatique et */
/* en Automatique. All rights reserved. This file is distributed */
/* under the terms of the GNU Library General Public License. */
/* */
/***********************************************************************/
/* $Id$ */
#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
static char sig_alt_stack[SIGSTKSZ];
static char * system_stack_top;
#if defined(TARGET_i386) && defined(SYS_linux_elf)
static void segv_handler(int signo, struct sigcontext sc)
{
char * fault_addr = (char *) sc.cr2;
#else
static void segv_handler(int signo, siginfo_t * info, void * context)
{
char * fault_addr = (char *) info->si_addr;
#endif
struct rlimit limit;
struct sigaction act;
static char buffer[4096];
if (getrlimit(RLIMIT_STACK, &limit) == 0 &&
((long) fault_addr & (sizeof(long) - 1)) == 0 &&
fault_addr < system_stack_top &&
fault_addr >= system_stack_top - limit.rlim_cur - 0x2000) {
_exit(0);
} else {
_exit(4);
}
}
void f(char * c);
void g(char * c) { char d[1024]; f(d); }
void f(char * c) { char d[1024]; g(d); }
int main(int argc, char ** argv)
{
struct sigaltstack stk;
struct sigaction act;
stk.ss_sp = sig_alt_stack;
stk.ss_size = SIGSTKSZ;
stk.ss_flags = 0;
#if defined(TARGET_i386) && defined(SYS_linux_elf)
act.sa_handler = (void (*)(int)) segv_handler;
act.sa_flags = SA_ONSTACK | SA_NODEFER;
#else
act.sa_sigaction = segv_handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
#endif
sigemptyset(&act.sa_mask);
system_stack_top = (char *) &act;
if (sigaltstack(&stk, NULL) != 0) { perror("sigaltstack"); return 2; }
if (sigaction(SIGSEGV, &act, NULL) != 0) { perror("sigaction"); return 2; }
f(NULL);
return 2;
}

14
configure vendored
View File

@ -753,6 +753,20 @@ else
debugger=""
fi
# Determine if system stack overflows can be detected
case "$arch,$model,$system" in
i386,*,*|alpha,*,digital)
if ./runtest -DTARGET_$arch -DSYS_$system stackov.c; then
echo "System stack overflow can be detected."
echo "#define HAS_STACK_OVERFLOW_DETECTION" >> s.h
else
echo "Cannot detect system stack overflow."
fi;;
*)
echo "Cannot detect system stack overflow.";;
esac
# Determine the target architecture for the "num" library
case "$host" in

View File

@ -0,0 +1,15 @@
let rec f x =
if x land 0xFFFF <> 0
then 1 + f (x + 1)
else
try
1 + f (x + 1)
with Stack_overflow ->
print_string "x = "; print_int x; print_newline();
raise Stack_overflow
let _ =
try
ignore(f 0)
with Stack_overflow ->
print_string "Stack overflow caught"; print_newline()