From d088a97f8268ed1cec756c52703304deda592811 Mon Sep 17 00:00:00 2001 From: agl Date: Tue, 7 Feb 2006 22:29:36 +0000 Subject: [PATCH] Add data/return stack under/over flow checks for POSIX This adds extra errors: #define ERROR_STACK_UNDERFLOW (12<<3) #define ERROR_STACK_OVERFLOW (13<<3) #define ERROR_RETSTACK_UNDERFLOW (14<<3) #define ERROR_RETSTACK_OVERFLOW (15<<3) On unix the data and return stacks have poison pages above and below them in memory. This patch adds checks to the sigv signal handler which checks to see if the faulting address is in one of these pages and, if so, triggers the correct error. To see: : data-overflow 1 2 3 data-overflow ; : ret-underflow V{ } set-callstack r> ; : ret-overflow 1 >r ret-overflow ; (to test data-underflow just call + with an empty stack) AGL --- library/tools/debugger.factor | 16 ++++++++++++++++ native/error.c | 12 ++++++++++++ native/error.h | 4 ++++ native/unix/signal.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/library/tools/debugger.factor b/library/tools/debugger.factor index 064a148603..e47487f8e3 100644 --- a/library/tools/debugger.factor +++ b/library/tools/debugger.factor @@ -48,6 +48,18 @@ SYMBOL: error-continuation : user-interrupt. ( obj -- ) "User interrupt" print drop ; +: stack-underflow. ( obj -- ) + "Stack underflow" print drop ; + +: stack-overflow. ( obj -- ) + "Stack overflow" print drop ; + +: return-stack-underflow. ( obj -- ) + "Return stack underflow" print drop ; + +: return-stack-overflow. ( obj -- ) + "Return stack overflow" print drop ; + PREDICATE: cons kernel-error ( obj -- ? ) dup first kernel-error = swap second 0 11 between? and ; @@ -66,6 +78,10 @@ M: kernel-error error. ( error -- ) [ heap-scan-error. ] [ undefined-symbol-error. ] [ user-interrupt. ] + [ stack-underflow. ] + [ stack-overflow. ] + [ return-stack-underflow. ] + [ return-stack-overflow . ] } dispatch ; M: no-method summary drop "No suitable method" ; diff --git a/native/error.c b/native/error.c index 9c7581f658..eedb6d18e1 100644 --- a/native/error.c +++ b/native/error.c @@ -70,6 +70,18 @@ void signal_error(int signal) cons(tag_fixnum(signal),F))),false); } +/* called from signal.c when a sigv tells us that we under/overflowed a page. + * The first bool is true if it was the return stack (otherwise it's the data + * stack) and the second bool is true if we overflowed it (otherwise we + * underflowed it) */ +void signal_stack_error(bool is_return_stack, bool is_overflow) +{ + CELL errors[] = { ERROR_STACK_UNDERFLOW, ERROR_STACK_OVERFLOW, + ERROR_RETSTACK_UNDERFLOW, ERROR_RETSTACK_OVERFLOW }; + const CELL error = errors[is_return_stack * 2 + is_overflow]; + throw_error(cons(userenv[ERROR_ENV], cons(error, F)), false); +} + void type_error(CELL type, CELL tagged) { CELL c = cons(tag_fixnum(type),cons(tagged,F)); diff --git a/native/error.h b/native/error.h index f2cde5dad3..d01131760f 100644 --- a/native/error.h +++ b/native/error.h @@ -10,6 +10,10 @@ #define ERROR_HEAP_SCAN (9<<3) #define ERROR_UNDEFINED_SYMBOL (10<<3) #define ERROR_USER_INTERRUPT (11<<3) +#define ERROR_STACK_UNDERFLOW (12<<3) +#define ERROR_STACK_OVERFLOW (13<<3) +#define ERROR_RETSTACK_UNDERFLOW (14<<3) +#define ERROR_RETSTACK_OVERFLOW (15<<3) /* Are we throwing an error? */ bool throwing; diff --git a/native/unix/signal.c b/native/unix/signal.c index 12ab7cbaf3..6984411bf7 100644 --- a/native/unix/signal.c +++ b/native/unix/signal.c @@ -1,6 +1,20 @@ #include "../factor.h" #include "mach_signal.h" +// this function tests if a given faulting location is in a poison page. The +// page address is taken from area + round_up_to_page_size(area_size) + +// pagesize*offset +static bool in_page(void *fault, void *i_area, CELL area_size, int offset) { + const int pagesize = getpagesize(); + intptr_t area = (intptr_t) i_area; + area += pagesize * ((area_size + (pagesize - 1)) / pagesize); + area += offset * pagesize; + + const int page = area / pagesize; + const int fault_page = (intptr_t)fault / pagesize; + return page == fault_page; +} + void signal_handler(int signal, siginfo_t* siginfo, void* uap) { if(nursery.here > nursery.limit) @@ -13,6 +27,27 @@ void signal_handler(int signal, siginfo_t* siginfo, void* uap) fprintf(stderr,"Code space exhausted\n"); factorbug(); } + /* we wish to catch the case where we underflow/overflow the data or + // return stacks. These stacks have poison pages above and below the + // memory so we just need to test if the faulting addresss is in one of + // these pages */ + + /* first, underflowing the data stack */ + else if(in_page(siginfo->si_addr, (void *) ds_bot, 0, -1)) + { + signal_stack_error(false, false); + } + else if(in_page(siginfo->si_addr, (void *) ds_bot, ds_size, 0)) { + signal_stack_error(false, true); + } + else if(in_page(siginfo->si_addr, (void *) cs_bot, 0, -1)) + { + signal_stack_error(true, false); + } + else if(in_page(siginfo->si_addr, (void *) cs_bot, cs_size, 0)) { + signal_stack_error(true, true); + } + else signal_error(signal); }