Detection du debordement de pile C
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@3621 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02master
parent
fbe4ff190f
commit
bf110cd0e2
|
@ -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);
|
||||
|
|
127
asmrun/signals.c
127
asmrun/signals.c
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue