diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index d4e7097..533437c 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -127,12 +127,23 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression, delay(50); // Brief delay before retry } + // Remove any incomplete file from previous attempt before retrying + if (SD.exists(tmpHtmlPath.c_str())) { + SD.remove(tmpHtmlPath.c_str()); + } + File tmpHtml; if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { continue; } success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); tmpHtml.close(); + + // If streaming failed, remove the incomplete file immediately + if (!success && SD.exists(tmpHtmlPath.c_str())) { + SD.remove(tmpHtmlPath.c_str()); + Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis()); + } } if (!success) { diff --git a/lib/Epub/Epub/blocks/TextBlock.cpp b/lib/Epub/Epub/blocks/TextBlock.cpp index bb8b14e..5af1634 100644 --- a/lib/Epub/Epub/blocks/TextBlock.cpp +++ b/lib/Epub/Epub/blocks/TextBlock.cpp @@ -4,11 +4,18 @@ #include void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const { + // Validate iterator bounds before rendering + if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) { + Serial.printf("[%lu] [TXB] Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), + (uint32_t)words.size(), (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size()); + return; + } + auto wordIt = words.begin(); auto wordStylesIt = wordStyles.begin(); auto wordXposIt = wordXpos.begin(); - for (int i = 0; i < words.size(); i++) { + for (size_t i = 0; i < words.size(); i++) { renderer.drawText(fontId, *wordXposIt + x, y, wordIt->c_str(), true, *wordStylesIt); std::advance(wordIt, 1); @@ -46,6 +53,13 @@ std::unique_ptr TextBlock::deserialize(File& file) { // words serialization::readPod(file, wc); + + // Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block) + if (wc > 10000) { + Serial.printf("[%lu] [TXB] Deserialization failed: word count %u exceeds maximum\n", millis(), wc); + return nullptr; + } + words.resize(wc); for (auto& w : words) serialization::readString(file, w); @@ -59,6 +73,13 @@ std::unique_ptr TextBlock::deserialize(File& file) { wordStyles.resize(sc); for (auto& s : wordStyles) serialization::readPod(file, s); + // Validate data consistency: all three lists must have the same size + if (wc != xc || wc != sc) { + Serial.printf("[%lu] [TXB] Deserialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), wc, xc, + sc); + return nullptr; + } + // style serialization::readPod(file, style);