fix(admin): stop the admin dispatcher from overflowing the ESP32 loopTask stack (#11239)

AdminModule::handleReceivedProtobuf carried a 3008-byte stack frame - 37% of
the 8 KB Arduino loopTask stack. GCC inlines the eight handleGet* helpers into
it, each of which builds a whole meshtastic_AdminMessage (480 B), so the
dispatcher reserved a slot for every one of them at once even though only one
case ever runs. Two more full AdminMessages lived directly in the function.

That left any admin write short of stack for what runs beneath it:
NodeDB::saveToDisk -> saveProto -> pb_encode -> SafeFile -> LittleFS -> flash.
On heltec-v4 the canary fired at 7824 of 8192 bytes while writing
/prefs/config.proto, so no setting ever persisted and the device rebooted.

Mark the response builders NOINLINE and move the module-API and observer
responses into their own functions. Pure refactor; measured on heltec-v4 the
dispatcher frame drops 3008 -> 384 bytes, taking the crashing path from 368
bytes of headroom to 2992.

Fixes #11237
This commit is contained in:
Ben Meadors
2026-07-26 21:34:38 +00:00
committed by GitHub
parent 69b68e2c42
commit 5c5cb094e6
3 changed files with 65 additions and 29 deletions
+10
View File
@@ -5,6 +5,16 @@
#include <iterator>
#include <stdint.h>
/// Keep a function out of line even when the compiler would rather inline it. Use on helpers that
/// hold a large object on the stack: inlining several of them into one caller makes that caller's
/// frame reserve every helper's locals at once, which on our 8 KB Arduino loopTask is enough to
/// overflow the stack (see issue #11237).
#if defined(__GNUC__)
#define NOINLINE __attribute__((noinline))
#else
#define NOINLINE
#endif
/// C++ v17+ clamp function, limits a given value to a range defined by lo and hi
template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi)
{