py: Get optional VM stack overflow check compiling and working again.
Changes to the layout of the bytecode header meant that this debug code was no longer compiling. This is now fixed and a new compile-time option is introduced, MICROPY_DEBUG_VM_STACK_OVERFLOW, to turn on this feature (which is disabled by default). This option is needed because more than one file needs to cooperate to make this check work.
This commit is contained in:
parent
b33f108cde
commit
6d19934463
@ -331,6 +331,10 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
// the highest slot in the state (fastn[0], see vm.c).
|
||||
n_state = 1;
|
||||
}
|
||||
#if MICROPY_DEBUG_VM_STACK_OVERFLOW
|
||||
// An extra slot in the stack is needed to detect VM stack overflow
|
||||
n_state += 1;
|
||||
#endif
|
||||
emit_write_code_info_uint(emit, n_state);
|
||||
emit_write_code_info_uint(emit, scope->exc_stack_size);
|
||||
}
|
||||
|
@ -409,6 +409,11 @@
|
||||
#define MICROPY_DEBUG_VERBOSE (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable a simple VM stack overflow check
|
||||
#ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW
|
||||
#define MICROPY_DEBUG_VM_STACK_OVERFLOW (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimisations */
|
||||
|
||||
|
30
py/objfun.c
30
py/objfun.c
@ -195,17 +195,12 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
|
||||
// than this will try to use the heap, with fallback to stack allocation.
|
||||
#define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t))
|
||||
|
||||
// Set this to 1 to enable a simple stack overflow check.
|
||||
#define VM_DETECT_STACK_OVERFLOW (0)
|
||||
|
||||
#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \
|
||||
{ \
|
||||
/* bytecode prelude: state size and exception stack size */ \
|
||||
n_state_out_var = mp_decode_uint_value(bytecode); \
|
||||
size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \
|
||||
\
|
||||
n_state_out_var += VM_DETECT_STACK_OVERFLOW; \
|
||||
\
|
||||
/* state size in bytes */ \
|
||||
state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \
|
||||
+ n_exc_stack * sizeof(mp_exc_stack_t); \
|
||||
@ -270,9 +265,17 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
||||
#else
|
||||
if (state_size > VM_MAX_STATE_ON_STACK) {
|
||||
code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size);
|
||||
#if MICROPY_DEBUG_VM_STACK_OVERFLOW
|
||||
if (code_state != NULL) {
|
||||
memset(code_state->state, 0, state_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (code_state == NULL) {
|
||||
code_state = alloca(sizeof(mp_code_state_t) + state_size);
|
||||
#if MICROPY_DEBUG_VM_STACK_OVERFLOW
|
||||
memset(code_state->state, 0, state_size);
|
||||
#endif
|
||||
state_size = 0; // indicate that we allocated using alloca
|
||||
}
|
||||
#endif
|
||||
@ -284,31 +287,34 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
||||
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);
|
||||
mp_globals_set(code_state->old_globals);
|
||||
|
||||
#if VM_DETECT_STACK_OVERFLOW
|
||||
#if MICROPY_DEBUG_VM_STACK_OVERFLOW
|
||||
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
|
||||
if (code_state->sp < code_state->state) {
|
||||
printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state);
|
||||
mp_printf(MICROPY_DEBUG_PRINTER, "VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
// We can't check the case when an exception is returned in state[n_state - 1]
|
||||
const byte *bytecode_ptr = mp_decode_uint_skip(mp_decode_uint_skip(self->bytecode));
|
||||
size_t n_pos_args = bytecode_ptr[1];
|
||||
size_t n_kwonly_args = bytecode_ptr[2];
|
||||
// We can't check the case when an exception is returned in state[0]
|
||||
// and there are no arguments, because in this case our detection slot may have
|
||||
// been overwritten by the returned exception (which is allowed).
|
||||
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) {
|
||||
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_pos_args + n_kwonly_args == 0)) {
|
||||
// Just check to see that we have at least 1 null object left in the state.
|
||||
bool overflow = true;
|
||||
for (size_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) {
|
||||
for (size_t i = 0; i < n_state - n_pos_args - n_kwonly_args; ++i) {
|
||||
if (code_state->state[i] == MP_OBJ_NULL) {
|
||||
overflow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overflow) {
|
||||
printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state);
|
||||
mp_printf(MICROPY_DEBUG_PRINTER, "VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mp_obj_t result;
|
||||
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
|
||||
|
Loading…
Reference in New Issue
Block a user