fix: don't boot-loop on a corrupted coredump

setup() prints the stored coredump summary on every boot and trusted its
backtrace depth. A half-written dump reads back as the 0xa5 stack fill, so
depth was 0xa5a5a5a5: the loop read past bt[16], snprintf ran past its
256-byte buffer once the size went negative, and the interrupt watchdog
reset the board. The dump stays in flash, so every boot hit it again
(seen 2026-10-21: 162 TG1WDT resets in a row, each stopping after "Cause:").

formatBacktrace() in Utils reads at most bt[]'s 16 frames and stops when the
buffer is full, and the line notes IDF's corrupted flag. The task name is
printed at most 16 chars, since exc_task isn't always terminated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-21 12:07:53 +02:00
parent b74f382650
commit 54641af039
4 changed files with 53 additions and 7 deletions

View file

@ -82,6 +82,9 @@ enum class heap_emit_t : uint8_t { none, client, broadcast, room };
// num is the socket client asked for, 255 for everyone. A broadcast goes out
// every intervalMs; in between only the clients in room 0 get one.
heap_emit_t heapEmitTarget(uint8_t num, uint32_t sinceLastMs, uint32_t intervalMs, bool roomHasClients);
// A coredump backtrace as " 0x%08x" per frame. bt holds maxFrames entries and
// depth is how many the dump claims are valid.
void formatBacktrace(char *buf, size_t size, const uint32_t *bt, size_t maxFrames, uint32_t depth);
// How well loop() keeps up: the passes it made per second and its longest
// pass, over the window since the last memStatus broadcast. Only the loop
// task calls record(), rate(), maxUs() and publish(). publish() closes the