From ed1a21fb7ba5dafc7b2bf6aa3a70c9378beaa222 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sun, 8 Mar 2026 16:26:52 +0100 Subject: [PATCH] Add magic value --- lib/Logging/Logging.cpp | 22 +++++++++++++++++----- lib/Logging/Logging.h | 8 ++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/Logging/Logging.cpp b/lib/Logging/Logging.cpp index 69a75cb6..3a516e0a 100644 --- a/lib/Logging/Logging.cpp +++ b/lib/Logging/Logging.cpp @@ -8,14 +8,25 @@ // Simple ring buffer log, useful for error reporting when we encounter a crash RTC_NOINIT_ATTR char logMessages[MAX_LOG_LINES][MAX_ENTRY_LEN]; RTC_NOINIT_ATTR size_t logHead = 0; +// Magic word written alongside logHead to detect uninitialized RTC memory. +// RTC_NOINIT_ATTR is not zeroed on cold boot, so logHead may appear in-range +// (0..MAX_LOG_LINES-1) by chance even though logMessages is garbage. The magic +// value is only set by clearLastLogs(), so its absence means the buffer was +// never properly initialized. +RTC_NOINIT_ATTR uint32_t rtcLogMagic; +static constexpr uint32_t fnv1a32(const char* s, uint32_t h = 2166136261u) { + return *s ? fnv1a32(s + 1, (h ^ static_cast(*s)) * 16777619u) : h; +} +static constexpr uint32_t LOG_RTC_MAGIC = fnv1a32("crosspoint-reader"); void addToLogRingBuffer(const char* message) { - // Add the message to the ring buffer, overwriting old messages if necessary - // If RTC_NOINIT_ATTR left logHead out of range on cold boot, all slots are - // garbage too — clear the entire buffer so subsequent reads are safe. - if (logHead >= MAX_LOG_LINES) { + // Add the message to the ring buffer, overwriting old messages if necessary. + // If the magic is wrong or logHead is out of range (RTC_NOINIT_ATTR garbage + // on cold boot), clear the entire buffer so subsequent reads are safe. + if (rtcLogMagic != LOG_RTC_MAGIC || logHead >= MAX_LOG_LINES) { memset(logMessages, 0, sizeof(logMessages)); logHead = 0; + rtcLogMagic = LOG_RTC_MAGIC; } strncpy(logMessages[logHead], message, MAX_ENTRY_LEN - 1); logMessages[logHead][MAX_ENTRY_LEN - 1] = '\0'; @@ -81,7 +92,7 @@ std::string getLastLogs() { } bool sanitizeLogHead() { - if (logHead >= MAX_LOG_LINES) { + if (rtcLogMagic != LOG_RTC_MAGIC || logHead >= MAX_LOG_LINES) { logHead = 0; return true; } @@ -93,4 +104,5 @@ void clearLastLogs() { logMessages[i][0] = '\0'; } logHead = 0; + rtcLogMagic = LOG_RTC_MAGIC; } diff --git a/lib/Logging/Logging.h b/lib/Logging/Logging.h index 2638c86e..47e8eb7d 100644 --- a/lib/Logging/Logging.h +++ b/lib/Logging/Logging.h @@ -57,10 +57,10 @@ void logPrintf(const char* level, const char* origin, const char* format, ...); std::string getLastLogs(); void clearLastLogs(); -// Clamps logHead into range. Returns true if logHead was out of range (repaired), -// which also means logMessages is untrusted garbage. Callers should call -// clearLastLogs() when this returns true so getLastLogs() does not dump corrupt -// data into crash reports. +// Validates the RTC log state (magic word + logHead range). Returns true if +// corruption was detected (magic mismatch or logHead out of range), meaning +// logMessages is untrusted garbage. Callers should call clearLastLogs() when +// this returns true so getLastLogs() does not dump corrupt data into crash reports. bool sanitizeLogHead(); class MySerialImpl : public Print {