fix(box): keep routine choice screen alive

On the first hop from the choice screen into a step screen,
build_step_screen() was calling lv_screen_load_anim with auto_del=true.
LVGL therefore deleted the outgoing choice screen (s_root) at the end of
the transition, leaving a dangling pointer in routine.c:s_root and
ui.c:s_screens[ROUTINE]. On the second entry into Routine mode,
lisael_ui_goto reused that freed pointer, causing a use-after-free.

Fix: use del_prev = (s_step_screen != NULL). When s_step_screen is NULL
the outgoing screen is the memoized s_root (auto_del=false, kept); when
non-NULL it is a transient step screen (auto_del=true, freed by LVGL as
before). show_bravo and the home-return paths are unchanged.
This commit is contained in:
L'électron rare
2026-06-21 11:23:01 +02:00
parent d809e8add4
commit 1491af2769
+7 -1
View File
@@ -324,7 +324,13 @@ static void build_step_screen(void)
lv_obj_set_style_text_font(dl, &lisael_font_24, 0); lv_obj_set_style_text_font(dl, &lisael_font_24, 0);
lv_obj_center(dl); lv_obj_center(dl);
lv_screen_load_anim(scr, LV_SCR_LOAD_ANIM_MOVE_LEFT, 200, 0, true); // Keep the memoized choice screen (s_root) alive on the first hop into a
// routine: when s_step_screen is NULL we are coming FROM the choice screen,
// so auto_del must be false to prevent LVGL from deleting s_root at the end
// of the transition. On subsequent step→step hops s_step_screen is the
// previous (transient) step screen, which LVGL can safely delete.
bool del_prev = (s_step_screen != NULL);
lv_screen_load_anim(scr, LV_SCR_LOAD_ANIM_MOVE_LEFT, 200, 0, del_prev);
s_step_screen = scr; s_step_screen = scr;
play_step_audio(); play_step_audio();
} }