fix(companion): nullptr-init screen pointers so a forgotten new() fails safe

Adding a screen touches 4 sites; 3 (member decl, gotoX decl, gotoX def) are
compile-checked, but a missed `new XScreen()` in begin() left the pointer
uninitialised and crashed at first navigation. Give every screen member an
in-class nullptr initialiser and bail early in setCurrScreen(nullptr) so the
mistake is an inert no-op instead of a null deref. Document the 4-site
registration contract on the member block.

A full registry table was considered and rejected: the named gotoXScreen()
methods are a depended-upon API (~30 call sites, menu dispatch + back-nav),
so a table would add an enum + indirection without removing them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MarekZegare4
2026-06-29 18:42:59 +02:00
co-authored by Claude Opus 4.8
parent eedd47d1e1
commit 15716d2b03
2 changed files with 28 additions and 18 deletions
+6 -1
View File
@@ -1748,8 +1748,13 @@ void UITask::userLedHandler() {
} }
void UITask::setCurrScreen(UIScreen* c) { void UITask::setCurrScreen(UIScreen* c) {
// Fail safe on a null target: a screen pointer left uninitialised (member
// declared + navigator wired, but the `new XScreen()` line forgotten in
// begin()) stays nullptr thanks to the in-class initialisers. Bail here so
// that mistake is an inert no-op instead of a null deref in render()/poll().
if (!c) return;
curr = c; curr = c;
if (c) c->onShow(); // central per-visit reset hook (see UIScreen::onShow) c->onShow(); // central per-visit reset hook (see UIScreen::onShow)
_next_refresh = 100; _next_refresh = 100;
} }
+22 -17
View File
@@ -68,23 +68,28 @@ class UITask : public AbstractUITask {
unsigned long _analogue_pin_read_millis = millis(); unsigned long _analogue_pin_read_millis = millis();
#endif #endif
UIScreen* splash; // Registering a new screen touches 4 sites: (1) the member below, (2) the
UIScreen* home; // `new XScreen()` in begin(), (3) the gotoXScreen() declaration further down,
UIScreen* settings; // (4) its one-line definition in UITask.cpp. Sites 1/3/4 are compile-checked;
UIScreen* quick_msg; // only a forgotten (2) can slip through — the nullptr initialisers here turn
UIScreen* tools_screen; // that into an inert no-op (see UITask::setCurrScreen) rather than a crash.
UIScreen* ringtone_edit; UIScreen* splash = nullptr;
UIScreen* bot_screen; UIScreen* home = nullptr;
UIScreen* nearby_screen; UIScreen* settings = nullptr;
UIScreen* dashboard_config; UIScreen* quick_msg = nullptr;
UIScreen* auto_advert_screen; UIScreen* tools_screen = nullptr;
UIScreen* live_share_screen; UIScreen* ringtone_edit = nullptr;
UIScreen* locator_screen; UIScreen* bot_screen = nullptr;
UIScreen* trail_screen; UIScreen* nearby_screen = nullptr;
UIScreen* compass_screen; UIScreen* dashboard_config = nullptr;
UIScreen* diag_screen; UIScreen* auto_advert_screen = nullptr;
UIScreen* repeater_screen; UIScreen* live_share_screen = nullptr;
UIScreen* curr; UIScreen* locator_screen = nullptr;
UIScreen* trail_screen = nullptr;
UIScreen* compass_screen = nullptr;
UIScreen* diag_screen = nullptr;
UIScreen* repeater_screen = nullptr;
UIScreen* curr = nullptr;
CayenneLPP _dash_lpp; CayenneLPP _dash_lpp;
TrailStore _trail; TrailStore _trail;
WaypointStore _waypoints; WaypointStore _waypoints;