stacks: move C shadow stack to a separate structure

This commit is contained in:
Daniel Kochmański 2024-04-03 13:41:45 +02:00
parent 593d9d2190
commit 45f3be3aa1
4 changed files with 49 additions and 51 deletions

View file

@ -34,7 +34,7 @@ cs_set_size(cl_env_ptr env, cl_index new_size)
struct rlimit rl;
if (!getrlimit(RLIMIT_STACK, &rl)) {
env->cs_max_size = rl.rlim_max;
env->c_stack.max_size = rl.rlim_max;
if (new_size > rl.rlim_cur) {
rl.rlim_cur = (new_size > rl.rlim_max) ? rl.rlim_max : new_size;
if (setrlimit(RLIMIT_STACK, &rl))
@ -52,29 +52,29 @@ cs_set_size(cl_env_ptr env, cl_index new_size)
new_size = rl.rlim_cur;
}
#ifdef ECL_DOWN_STACK
env->cs_barrier = env->cs_org - new_size;
env->c_stack.max = env->c_stack.org - new_size;
#else
env->cs_barrier = env->cs_org + new_size;
env->c_stack.max = env->c_stack.org + new_size;
#endif
}
#endif
env->cs_limit_size = new_size - (2*margin);
env->c_stack.limit_size = new_size - (2*margin);
#ifdef ECL_DOWN_STACK
if (&foo > (env->cs_org - new_size) + 16) {
env->cs_limit = (env->cs_org - new_size) + (2*margin);
if (env->cs_limit < env->cs_barrier)
env->cs_barrier = env->cs_limit;
if (&foo > (env->c_stack.org - new_size) + 16) {
env->c_stack.limit = (env->c_stack.org - new_size) + (2*margin);
if (env->c_stack.limit < env->c_stack.max)
env->c_stack.max = env->c_stack.limit;
}
#else
if (&foo < (env->cs_org + new_size) - 16) {
env->cs_limit = (env->cs_org + new_size) - (2*margin);
if (env->cs_limit > env->cs_barrier)
env->cs_barrier = env->cs_limit;
if (&foo < (env->c_stack.org + new_size) - 16) {
env->c_stack.limit = (env->c_stack.org + new_size) - (2*margin);
if (env->c_stack.limit > env->c_stack.max)
env->c_stack.max = env->c_stack.limit;
}
#endif
else
ecl_internal_error("Can't set the size of the C stack: sanity check failed");
env->cs_size = new_size;
env->c_stack.size = new_size;
}
void
@ -86,18 +86,18 @@ ecl_cs_overflow(void)
";;;\n\n";
cl_env_ptr env = ecl_process_env();
cl_index margin = ecl_option_values[ECL_OPT_C_STACK_SAFETY_AREA];
cl_index size = env->cs_size;
cl_index size = env->c_stack.size;
#ifdef ECL_DOWN_STACK
if (env->cs_limit > env->cs_org - size)
env->cs_limit -= margin;
if (env->c_stack.limit > env->c_stack.org - size)
env->c_stack.limit -= margin;
#else
if (env->cs_limit < env->cs_org + size)
env->cs_limit += margin;
if (env->c_stack.limit < env->c_stack.org + size)
env->c_stack.limit += margin;
#endif
else
ecl_unrecoverable_error(env, stack_overflow_msg);
if (env->cs_max_size == (cl_index)0 || env->cs_size < env->cs_max_size)
if (env->c_stack.max_size == (cl_index)0 || env->c_stack.size < env->c_stack.max_size)
si_serror(6, @"Extend stack size",
@'ext::stack-overflow',
@':size', ecl_make_fixnum(size),
@ -108,8 +108,8 @@ ecl_cs_overflow(void)
@':size', ECL_NIL,
@':type', @'ext::c-stack');
size += size/2;
if (size > env->cs_max_size)
size = env->cs_max_size;
if (size > env->c_stack.max_size)
size = env->c_stack.max_size;
cs_set_size(env, size);
}
@ -119,17 +119,17 @@ ecl_cs_set_org(cl_env_ptr env)
#ifdef GBC_BOEHM
struct GC_stack_base base;
if (GC_get_stack_base(&base) == GC_SUCCESS)
env->cs_org = (char*)base.mem_base;
env->c_stack.org = (char*)base.mem_base;
else
#endif
{
/* Rough estimate. Not very safe. We assume that cl_boot()
* is invoked from the main() routine of the program.
*/
env->cs_org = (char*)(&env);
env->c_stack.org = (char*)(&env);
}
env->cs_barrier = env->cs_org;
env->cs_max_size = 0;
env->c_stack.max = env->c_stack.org;
env->c_stack.max_size = 0;
cs_set_size(env, ecl_option_values[ECL_OPT_C_STACK_SIZE]);
}
@ -833,7 +833,7 @@ si_get_limit(cl_object type)
else if (type == @'ext::binding-stack')
output = env->bds_stack.limit_size;
else if (type == @'ext::c-stack')
output = env->cs_limit_size;
output = env->c_stack.limit_size;
else if (type == @'ext::lisp-stack')
output = env->stack_limit_size;
else if (type == @'ext::heap-size') {
@ -853,7 +853,7 @@ si_reset_margin(cl_object type)
else if (type == @'ext::binding-stack')
ecl_bds_set_size(env, env->bds_stack.size);
else if (type == @'ext::c-stack')
cs_set_size(env, env->cs_size);
cs_set_size(env, env->c_stack.size);
else
ecl_return1(env, ECL_NIL);

View file

@ -829,16 +829,16 @@ handler_fn_prototype(sigsegv_handler, int sig, siginfo_t *info, void *aux)
# endif /* ECL_USE_MPROTECT */
# ifdef ECL_DOWN_STACK
if (sig == SIGSEGV &&
(char*)info->si_addr > the_env->cs_barrier &&
(char*)info->si_addr <= the_env->cs_org) {
(char*)info->si_addr > the_env->c_stack.max &&
(char*)info->si_addr <= the_env->c_stack.org) {
unblock_signal(the_env, sig);
ecl_unrecoverable_error(the_env, stack_overflow_msg);
return;
}
# else
if (sig == SIGSEGV &&
(char*)info->si_addr < the_env->cs_barrier &&
(char*)info->si_addr >= the_env->cs_org) {
(char*)info->si_addr < the_env->c_stack.max &&
(char*)info->si_addr >= the_env->c_stack.org) {
unblock_signal(the_env, sig);
ecl_unrecoverable_error(the_env, stack_overflow_msg);
return;

View file

@ -44,6 +44,21 @@ struct ecl_history_stack {
struct ecl_ihs_frame *top;
};
/* The following pointers to the C Stack are used to ensure that a recursive
* function does not enter an infinite loop and exhausts all memory. They will
* eventually disappear, because most operating systems already take care of
* this. */
struct ecl_c_stack {
cl_index max_size; /* maximum possible size */
cl_index size; /* current size */
cl_index limit_size; /* maximum size minus safety area */
char *org; /* origin address */
char *max; /* overflow address (real maximum address) */
char *limit; /* overflow address (spares recovery area) */
};
/*
* Per-thread data.
*/
@ -78,24 +93,7 @@ struct cl_env_struct {
struct ecl_binding_stack bds_stack;
struct ecl_frames_stack frs_stack;
struct ecl_history_stack ihs_stack;
/*
* The following pointers to the C Stack are used to ensure that a
* recursive function does not enter an infinite loop and exhausts all
* memory. They will eventually disappear, because most operating
* systems already take care of this.
*/
cl_index cs_size; /* current size */
cl_index cs_limit_size; /* current size minus safety area */
cl_index cs_max_size; /* maximum possible size */
char *cs_org; /* origin address */
char *cs_limit; /* limit address; if the stack pointer
goes beyond this value, a stack
overflow will be signaled ... */
char *cs_barrier; /* ... but the area up to cs_barrier
is still available to allow
programs to recover from the
stack overflow */
struct ecl_c_stack c_stack;
/* Private variables used by different parts of ECL: */
/* ... the reader and printer ... */

View file

@ -27,10 +27,10 @@ extern "C" {
#ifdef ECL_DOWN_STACK
#define ecl_cs_check(env,var) \
if (ecl_unlikely((char*)(&var) <= (env)->cs_limit)) ecl_cs_overflow()
if (ecl_unlikely((char*)(&var) <= (env)->c_stack.limit)) ecl_cs_overflow()
#else
#define ecl_cs_check(env,var) \
if (ecl_unlikely((char*)(&var) >= (env)->cs_limit)) ecl_cs_overflow()
if (ecl_unlikely((char*)(&var) >= (env)->c_stack.limit)) ecl_cs_overflow()
#endif
/*********************************************************