## Summary * **What is the goal of this PR?** On a cold boot (or after a crash that corrupts RTC RAM), logHead contains garbage. Then addToLogRingBuffer does: ``strncpy(logMessages[logHead], message, MAX_ENTRY_LEN - 1); `` With garbage logHead, this computes a completely invalid address. The % MAX_LOG_LINES guard on line 16 only runs after the bad store, which is too late. The fix is to clamp logHead before use. ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ (did use claude for the magic hash value)
85 lines
2.4 KiB
C++
85 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <HardwareSerial.h>
|
|
|
|
#include <string>
|
|
|
|
/*
|
|
Define ENABLE_SERIAL_LOG to enable logging
|
|
Can be set in platformio.ini build_flags or as a compile definition
|
|
|
|
Define LOG_LEVEL to control log verbosity:
|
|
0 = ERR only
|
|
1 = ERR + INF
|
|
2 = ERR + INF + DBG
|
|
If not defined, defaults to 0
|
|
|
|
If you have a legitimate need for raw Serial access (e.g., binary data,
|
|
special formatting), use the underlying logSerial object directly:
|
|
logSerial.printf("Special case: %d\n", value);
|
|
logSerial.write(binaryData, length);
|
|
|
|
The logSerial reference (defined below) points to the real Serial object and
|
|
won't trigger deprecation warnings.
|
|
*/
|
|
|
|
#ifndef LOG_LEVEL
|
|
#define LOG_LEVEL 0
|
|
#endif
|
|
|
|
static HWCDC& logSerial = Serial;
|
|
|
|
void logPrintf(const char* level, const char* origin, const char* format, ...);
|
|
|
|
#ifdef ENABLE_SERIAL_LOG
|
|
#if LOG_LEVEL >= 0
|
|
#define LOG_ERR(origin, format, ...) logPrintf("[ERR]", origin, format "\n", ##__VA_ARGS__)
|
|
#else
|
|
#define LOG_ERR(origin, format, ...)
|
|
#endif
|
|
|
|
#if LOG_LEVEL >= 1
|
|
#define LOG_INF(origin, format, ...) logPrintf("[INF]", origin, format "\n", ##__VA_ARGS__)
|
|
#else
|
|
#define LOG_INF(origin, format, ...)
|
|
#endif
|
|
|
|
#if LOG_LEVEL >= 2
|
|
#define LOG_DBG(origin, format, ...) logPrintf("[DBG]", origin, format "\n", ##__VA_ARGS__)
|
|
#else
|
|
#define LOG_DBG(origin, format, ...)
|
|
#endif
|
|
#else
|
|
#define LOG_DBG(origin, format, ...)
|
|
#define LOG_ERR(origin, format, ...)
|
|
#define LOG_INF(origin, format, ...)
|
|
#endif
|
|
|
|
std::string getLastLogs();
|
|
void clearLastLogs();
|
|
// 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 {
|
|
public:
|
|
void begin(unsigned long baud) { logSerial.begin(baud); }
|
|
|
|
// Support boolean conversion for compatibility with code like:
|
|
// if (Serial) or while (!Serial)
|
|
operator bool() const { return logSerial; }
|
|
|
|
__attribute__((deprecated("Use LOG_* macro instead"))) size_t printf(const char* format, ...);
|
|
size_t write(uint8_t b) override;
|
|
size_t write(const uint8_t* buffer, size_t size) override;
|
|
void flush() override;
|
|
static MySerialImpl instance;
|
|
};
|
|
|
|
#ifdef Serial
|
|
#undef Serial
|
|
#endif
|
|
#define Serial MySerialImpl::instance
|