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.
pull/4401/head
Damien George 2019-01-04 17:09:41 +11:00
rodzic b33f108cde
commit 6d19934463
3 zmienionych plików z 27 dodań i 12 usunięć

Wyświetl plik

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

Wyświetl plik

@ -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 */

Wyświetl plik

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