~ chicken-core (chicken-5) a4c3e1411eba89f0dcc05dc7ef5ec205a7915e69
commit a4c3e1411eba89f0dcc05dc7ef5ec205a7915e69 Author: Evan Hanson <evhan@foldling.org> AuthorDate: Thu Sep 8 22:32:21 2016 +1200 Commit: Evan Hanson <evhan@foldling.org> CommitDate: Sat Sep 10 23:07:10 2016 +1200 Detect and signal error on stack overflow in `apply` When a demand for nursery space is unsatisfied even after popping the stack and reinvoking the caller, going back to C_save_and_reclaim to try to reclaim space *again* just leads to an infinite loop. Since there's not much else we can do in this situation, it's better to signal the problem as a Scheme-level error. To do this, we can just remember that there was a stack demand when jumping into the GC from C_apply or C_apply_values and, if the same demand fails when we bounce back and try again, we barf. The one tricky thing to this is that we must forget the remembered demand if the jump to the GC is redirected to the interrupt handler. Otherwise, the next call to C_apply/C_apply_values would only get one chance to demand nursery space. diff --git a/chicken.h b/chicken.h index b076661b..9e736660 100644 --- a/chicken.h +++ b/chicken.h @@ -1132,7 +1132,7 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret; # define C_stress 1 #endif -#define C_stack_overflow_check C_stack_check1(C_stack_overflow()) +#define C_stack_overflow_check C_stack_check1(C_stack_overflow(NULL)) /* TODO: The C_scratch_usage checks should probably be moved. Maybe * we should add a core#allocate_scratch_inline which will insert @@ -1847,7 +1847,7 @@ C_fctexport void C_bad_argc(int c, int n) C_noret; C_fctexport void C_bad_min_argc(int c, int n) C_noret; C_fctexport void C_bad_argc_2(int c, int n, C_word closure) C_noret; C_fctexport void C_bad_min_argc_2(int c, int n, C_word closure) C_noret; -C_fctexport void C_stack_overflow(void) C_noret; +C_fctexport void C_stack_overflow(C_char *loc) C_noret; C_fctexport void C_unbound_error(C_word sym) C_noret; C_fctexport void C_no_closure_error(C_word x) C_noret; C_fctexport void C_div_by_zero_error(char *loc) C_noret; diff --git a/runtime.c b/runtime.c index fea87140..403ac8ff 100644 --- a/runtime.c +++ b/runtime.c @@ -483,6 +483,7 @@ static volatile C_TLS int static C_TLS unsigned int mutation_count, tracked_mutation_count, + stack_check_demand, stack_size; static C_TLS int chicken_is_initialized; #ifdef HAVE_SIGSETJMP @@ -2586,17 +2587,12 @@ void C_bad_min_argc_2(int c, int n, C_word closure) } -void C_stack_overflow(void) +void C_stack_overflow(C_char *loc) { - barf(C_STACK_OVERFLOW_ERROR, NULL); + barf(C_STACK_OVERFLOW_ERROR, loc); } -void C_stack_overflow_with_msg(C_char *msg) -{ - barf(C_STACK_OVERFLOW_ERROR, NULL); -} - void C_unbound_error(C_word sym) { barf(C_UNBOUND_VARIABLE_ERROR, NULL, sym); @@ -3285,8 +3281,10 @@ C_regparm void C_fcall C_reclaim(void *trampoline, C_word c) /* assert(C_timer_interrupt_counter >= 0); */ - if(pending_interrupts_count > 0 && C_interrupts_enabled) + if(pending_interrupts_count > 0 && C_interrupts_enabled) { + stack_check_demand = 0; /* forget demand: we're not going to gc yet */ handle_interrupt(trampoline); + } cell.enabled = 0; cell.event = C_DEBUG_GC; @@ -7460,8 +7458,14 @@ void C_ccall C_apply(C_word c, C_word *av) len = C_unfix(C_u_i_length(lst)); av2_size = 2 + non_list_args + len; - if(!C_demand(av2_size)) + if(C_demand(av2_size)) + stack_check_demand = 0; + else if(stack_check_demand) + C_stack_overflow("apply"); + else { + stack_check_demand = av2_size; C_save_and_reclaim((void *)C_apply, c, av); + } av2 = ptr = C_alloc(av2_size); *(ptr++) = fn; @@ -7605,8 +7609,14 @@ void C_ccall C_apply_values(C_word c, C_word *av) len = C_unfix(C_u_i_length(lst)); n = len + 1; - if (!C_demand(n)) + if(C_demand(n)) + stack_check_demand = 0; + else if(stack_check_demand) + C_stack_overflow("apply"); + else { + stack_check_demand = n; C_save_and_reclaim((void *)C_apply_values, c, av); + } av2 = C_alloc(n); av2[ 0 ] = k;Trap