From f4b08ea435d86c61b8d49da3cd2325aecf514dcd Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Mon, 14 Nov 2022 10:59:42 +0100 Subject: [PATCH 1/2] py/objexcept: Add uncatchable SystemAbort exception. This adds an exception type that forces MicroPython to exit even if the user MicroPython script catches all exceptions. This exception can be raised by C code to force MicroPython to exit for safety reasons, such as very low battery or very high temperatures. --- py/mpconfig.h | 6 ++++++ py/obj.h | 3 +++ py/objexcept.c | 6 ++++++ py/vm.c | 8 ++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 0ae6fcdd1169f..97f99d06d85c2 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -658,6 +658,12 @@ #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. +#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 diff --git a/py/obj.h b/py/obj.h index b5b855bad395c..066ab5b9fb45a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -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. diff --git a/py/objexcept.c b/py/objexcept.c index 515cbe7425b03..f32c5e15fc935 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -376,6 +376,12 @@ 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. Can be used to force MicroPython to exit from C code. +MP_DEFINE_EXCEPTION(SystemAbort, BaseException) +#endif + // *FORMAT-ON* mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { diff --git a/py/vm.c b/py/vm.c index 9273dda02eead..6f29e3c54d115 100644 --- a/py/vm.c +++ b/py/vm.c @@ -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 From ddae9a3305e7db1e53e0a85bd85c0f70fbc42676 Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Thu, 17 Nov 2022 10:47:11 +0100 Subject: [PATCH 2/2] py/scheduler: Schedule SystemExit or SystemAbort. This implements mp_sched_system_exit_or_abort(), which can be used to schedule a SystemExit or SystemAbort on the main thread. This can be used by async sources to exit MicroPython if requested by a firmware process. Use abort=true if the MicroPython script must not be able to catch it, not even with a bare except. The implementation is similar to mp_sched_keyboard_interrupt(). Signed-off-by: Laurens Valk --- py/mpconfig.h | 3 ++- py/mpstate.h | 5 +++++ py/objexcept.c | 5 +++-- py/runtime.c | 8 ++++++++ py/runtime.h | 3 +++ py/scheduler.c | 11 +++++++++++ 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 97f99d06d85c2..24f5fbf1265bb 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -659,7 +659,8 @@ #endif // Whether to provide the SystemAbort exception, used to exit MicroPython -// even if user code catches all exceptions. +// 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 diff --git a/py/mpstate.h b/py/mpstate.h index ba47c7648235b..24d92d8a6e535 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -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; diff --git a/py/objexcept.c b/py/objexcept.c index f32c5e15fc935..dd548a6cd8143 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -377,8 +377,9 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) */ #if MICROPY_ENABLE_SYSTEM_ABORT -// Exception that can't be raised or caught by user code, not even with a -// bare except. Can be used to force MicroPython to exit from C code. +// 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 diff --git a/py/runtime.c b/py/runtime.c index 23fae6041dd0f..bb26f21e8db4d 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -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; diff --git a/py/runtime.h b/py/runtime.h index 36b3caa6c73e6..c50e40a568968 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -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 diff --git a/py/scheduler.c b/py/scheduler.c index db090b09911ce..3bad3f5ca84dd 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -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)) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy