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
darcs
agl 2006-02-07 22:29:36 +00:00
parent f353ea347b
commit d088a97f82
4 changed files with 67 additions and 0 deletions

View File

@ -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" ;

View File

@ -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));

View File

@ -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;

View File

@ -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);
}