From 8e596c60505c21768064afaeee6ff7814668b44a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 20 Aug 2025 16:16:15 -0500 Subject: [PATCH 1/3] unix: Don't crash if heap locked in prompt_write_history. Signed-off-by: Jeff Epler --- ports/unix/input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/unix/input.c b/ports/unix/input.c index 31926a5a8e1af..260e9eac8c9db 100644 --- a/ports/unix/input.c +++ b/ports/unix/input.c @@ -104,6 +104,9 @@ void prompt_write_history(void) { #if MICROPY_USE_READLINE == 1 char *home = getenv("HOME"); if (home != NULL) { + if (MP_STATE_THREAD(gc_lock_depth) != 0) { + return; + } vstr_t vstr; vstr_init(&vstr, 50); vstr_printf(&vstr, "%s/.micropython.history", home); From 065f13b11490827900fac9ddc30db891916c9d99 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 20 Aug 2025 16:17:19 -0500 Subject: [PATCH 2/3] unix: Unlock heap before readline. This is intended to be equivalent to the unlock in shared/runtime/pyexec.c. Signed-off-by: Jeff Epler --- ports/unix/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/unix/main.c b/ports/unix/main.c index 51d99ce5f1510..2fcdc0fdf881b 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -209,6 +209,11 @@ static int do_repl(void) { mp_hal_stdio_mode_raw(); input_restart: + // If the GC is locked at this point there is no way out except a reset, + // so force the GC to be unlocked to help the user debug what went wrong. + if (MP_STATE_THREAD(gc_lock_depth) != 0) { + MP_STATE_THREAD(gc_lock_depth) = 0; + } vstr_reset(&line); int ret = readline(&line, mp_repl_get_ps1()); mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; From 3bad046b5f5704a8ef686d5cd91cf1e2405003d2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 20 Aug 2025 17:29:45 -0500 Subject: [PATCH 3/3] tests: Add test for heap lock in REPL. Signed-off-by: Jeff Epler --- tests/cmdline/repl_lock.py | 7 +++++++ tests/cmdline/repl_lock.py.exp | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/cmdline/repl_lock.py create mode 100644 tests/cmdline/repl_lock.py.exp diff --git a/tests/cmdline/repl_lock.py b/tests/cmdline/repl_lock.py new file mode 100644 index 0000000000000..c96e01309c70e --- /dev/null +++ b/tests/cmdline/repl_lock.py @@ -0,0 +1,7 @@ +import micropython +micropython.heap_lock() +1+1 +micropython.heap_lock() +#################################################################### +micropython.heap_lock() +raise SystemExit diff --git a/tests/cmdline/repl_lock.py.exp b/tests/cmdline/repl_lock.py.exp new file mode 100644 index 0000000000000..a7afd2ef3a029 --- /dev/null +++ b/tests/cmdline/repl_lock.py.exp @@ -0,0 +1,10 @@ +MicroPython \.\+ version +Use \.\+ +>>> import micropython +>>> micropython.heap_lock() +>>> 1+1 +2 +>>> micropython.heap_lock() +>>> #################################################################### +>>> micropython.heap_lock() +>>> raise SystemExit