mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-16 00:21:35 +10:00
Refine message history limits for resource-constrained builds and cap cached lines to prevent heap overflow
This commit is contained in:
+2
-1
@@ -23,7 +23,8 @@
|
||||
#ifndef MESSAGE_HISTORY_LIMIT
|
||||
#if defined(ARCH_ESP32) && \
|
||||
!(defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2))
|
||||
// Original ESP32 has no PSRAM; keep fewer messages in RAM
|
||||
// Baseline ESP32 (non-PSRAM variants) has limited heap; reduce message history on resource-constrained builds.
|
||||
// Override with -DMESSAGE_HISTORY_LIMIT=N if needed.
|
||||
#define MESSAGE_HISTORY_LIMIT 10
|
||||
#else
|
||||
#define MESSAGE_HISTORY_LIMIT 20
|
||||
|
||||
@@ -422,17 +422,19 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
std::vector<bool> isMine; // track alignment
|
||||
std::vector<bool> isHeader; // track header lines
|
||||
std::vector<AckStatus> ackForLine;
|
||||
// Reserve based on filtered count but cap at the configured message limit × a
|
||||
// worst-case lines-per-message (1 header + up to 4 body lines). This prevents
|
||||
// a large single allocation — and the persistent capacity that swap() transfers
|
||||
// into cachedLines — from growing beyond what the store can ever hold.
|
||||
// Hard limit on total cached lines to prevent unbounded growth from a single long message.
|
||||
// Reserve based on filtered count but cap at the configured message limit × a worst-case
|
||||
// lines-per-message. For a display rendering only ~5-30 lines at a time, caching more than
|
||||
// this limit wastes heap. Stop appending once we reach MAX_CACHED_LINES to prevent a single
|
||||
// message from blowing out the heap.
|
||||
constexpr size_t MAX_LINES_PER_MSG = 5U;
|
||||
constexpr size_t MAX_CACHED_LINES = 100U; // ~5-6KB for std::string overhead on 32-bit (if each ~50-60 bytes avg)
|
||||
const size_t estimatedLines =
|
||||
std::min(filtered.size() * MAX_LINES_PER_MSG, static_cast<size_t>(MAX_MESSAGES_SAVED) * MAX_LINES_PER_MSG);
|
||||
allLines.reserve(estimatedLines);
|
||||
isMine.reserve(estimatedLines);
|
||||
isHeader.reserve(estimatedLines);
|
||||
ackForLine.reserve(estimatedLines);
|
||||
allLines.reserve(std::min(estimatedLines, MAX_CACHED_LINES));
|
||||
isMine.reserve(std::min(estimatedLines, MAX_CACHED_LINES));
|
||||
isHeader.reserve(std::min(estimatedLines, MAX_CACHED_LINES));
|
||||
ackForLine.reserve(std::min(estimatedLines, MAX_CACHED_LINES));
|
||||
|
||||
for (auto it = filtered.rbegin(); it != filtered.rend(); ++it) {
|
||||
const auto &m = *it;
|
||||
@@ -576,11 +578,18 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
|
||||
int wrapWidth = mine ? rightTextWidth : leftTextWidth;
|
||||
std::vector<std::string> wrapped = generateLines(display, "", msgText, wrapWidth);
|
||||
// Per-message wrap-line limit: even if wrapping produces many lines, cap them to prevent
|
||||
// a single long message from consuming most or all of the cache.
|
||||
constexpr size_t MAX_WRAPPED_LINES_PER_MSG = 20U;
|
||||
size_t wrappedCount = 0;
|
||||
for (auto &ln : wrapped) {
|
||||
if (allLines.size() >= MAX_CACHED_LINES || wrappedCount >= MAX_WRAPPED_LINES_PER_MSG)
|
||||
break; // Cache limit or per-message limit reached; stop adding lines from this message
|
||||
allLines.emplace_back(std::move(ln));
|
||||
isMine.push_back(mine);
|
||||
isHeader.push_back(false);
|
||||
ackForLine.push_back(AckStatus::NONE);
|
||||
++wrappedCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user