8000 py/objexcept: Add uncatchable SystemAbort exception. by laurensvalk · Pull Request #9949 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

py/objexcept: Add uncatchable SystemAbort exception. #9949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,13 @@
#define MICROPY_KBD_EXCEPTION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif

// Whether to provide the SystemAbort exception, used to exit MicroPython
// even if user code catches all exceptions. This also provides
// mp_sched_system_exit_or_abort() to schedule the mp_system_exception object.
#ifndef MICROPY_ENABLE_SYSTEM_ABORT
#define MICROPY_ENABLE_SYSTEM_ABORT (0)
#endif

// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt
// handler) - if supported by a particular port.
#ifndef MICROPY_ASYNC_KBD_INTR
Expand Down
5 changes: 5 additions & 0 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ typedef struct _mp_state_vm_t {
mp_obj_exception_t mp_kbd_exception;
#endif

#if MICROPY_ENABLE_SYSTEM_ABORT
// exception object of type SystemExit or SystemAbort
mp_obj_exception_t mp_system_exception;
#endif

// dictionary with loaded modules (may be exposed as sys.modules)
mp_obj_dict_t mp_loaded_modules_dict;

Expand Down
3 changes: 3 additions & 0 deletions py/obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,9 @@ extern const mp_obj_type_t mp_type_UnicodeError;
extern const mp_obj_type_t mp_type_ValueError;
extern const mp_obj_type_t mp_type_ViperTypeError;
extern const mp_obj_type_t mp_type_ZeroDivisionError;
#if MICROPY_ENABLE_SYSTEM_ABORT
extern const mp_obj_type_t mp_type_SystemAbort;
#endif

// Constant objects, globally accessible: None, False, True
// These should always be accessed via the below macros.
Expand Down
7 changes: 7 additions & 0 deletions py/objexcept.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,13 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(ResourceWarning, Warning)
*/

#if MICROPY_ENABLE_SYSTEM_ABORT
// Exception that can't be raised or caught by user code, not even with a bare
// except. Do not raise directly but use mp_sched_system_exit_or_abort(true) to
// schedule it on the main thread.
MP_DEFINE_EXCEPTION(SystemAbort, BaseException)
#endif

// *FORMAT-ON*

mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
Expand Down
8 changes: 8 additions & 0 deletions py/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ void mp_init(void) {
MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
#endif

#if MICROPY_ENABLE_SYSTEM_ABORT
// initialise the exception object for raising SystemExit or SystemAbort
MP_STATE_VM(mp_system_exception).traceback_alloc = 0;
MP_STATE_VM(mp_system_exception).traceback_len = 0;
MP_STATE_VM(mp_system_exception).traceback_data = NULL;
MP_STATE_VM(mp_system_exception).args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
#endif

#if MICROPY_ENABLE_COMPILER
// optimization disabled by default
MP_STATE_VM(mp_optimise_value) = 0;
Expand Down
3 changes: 3 additions & 0 deletions py/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ void mp_deinit(void);

void mp_sched_exception(mp_obj_t exc);
void mp_sched_keyboard_interrupt(void);
#if MICROPY_ENABLE_SYSTEM_ABORT
void mp_sched_system_exit_or_abort(bool abort);
#endif
void mp_handle_pending(bool raise_exc);

#if MICROPY_ENABLE_SCHEDULER
Expand Down
11 changes: 11 additions & 0 deletions py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ void MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(mp_sched_keyboard_interrupt)(void)
}
#endif

#if MICROPY_ENABLE_SYSTEM_ABORT
// Schedules SystemExit or SystemAbort on the main thread. Can be used by
// async sources to exit MicroPython. Use abort=true if the MicroPython script
// must not be able to catch it, not even with a bare except.
void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_system_exit_or_abort)(bool abort) {
MP_STATE_VM(mp_system_exception).base.type = abort ?
&mp_type_SystemAbort : &mp_type_SystemExit;
mp_sched_exception(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_system_exception)));
}
#endif

#if MICROPY_ENABLE_SCHEDULER

#define IDX_MASK(i) ((i) & (MICROPY_SCHEDULER_DEPTH - 1))
Expand Down
8 changes: 6 additions & 2 deletions py/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1441,8 +1441,12 @@ unwind_jump:;
POP_EXC_BLOCK();
}

if (exc_sp >= exc_stack) {
// catch exception and pass to byte code
if (exc_sp >= exc_stack
#if MICROPY_ENABLE_SYSTEM_ABORT
&& !mp_obj_exception_match(MP_OBJ_FROM_PTR(nlr.ret_val), MP_OBJ_FROM_PTR(&mp_type_SystemAbort))
#endif
) {
// catch exception (but not SystemAbort) and pass to byte code
code_state->ip = exc_sp->handler;
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
// save this exception in the stack so it can be used in a reraise, if needed
Expand Down
0