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) AGLdarcs
parent
f353ea347b
commit
d088a97f82
|
@ -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" ;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue