From a95a63b75313c6fdcb63d339635e6bc92dd8816c Mon Sep 17 00:00:00 2001 From: Uri Tauber <142022451+Uri-Tauber@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:57:40 +0200 Subject: [PATCH] fix: load access fault crash (#1370) ## Summary Fixes a crash (load access fault) when opening EPUB chapters whose first text block exceeds 750 words. ## Changes * **Crash fix (`addLineToPage`)**: Added a null guard for `currentPage`. If `makePages()` hasn't run yet (which can happen when the first block triggers the "text block too long" split path), the page is now created on demand. * **Layout fix (`characterData`)**: The early-split path previously used `viewportWidth`, ignoring CSS margins and padding. It now computes `effectiveWidth` using `totalHorizontalInset()`, consistent with `makePages()`. ## Additional Context * Crash signature: `MCAUSE=0x5` (load access fault), `A0=0x0` (`Page*` null), `MTVAL=0x4 / 0x8` (offsets into `Page::elements`). * Confirmed in two user reports reported in #1328 * Tested on PR #1357 (not on `master`). --- ### 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? _**< PARTIALLY >**_ --- lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index 1df3ceab..241e7e0d 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -772,8 +772,12 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char // Spotted when reading Intermezzo, there are some really long text blocks in there. if (self->currentTextBlock->size() > 750) { LOG_DBG("EHP", "Text block too long, splitting into multiple pages"); + const int horizontalInset = self->currentTextBlock->getBlockStyle().totalHorizontalInset(); + const uint16_t effectiveWidth = (horizontalInset < self->viewportWidth) + ? static_cast(self->viewportWidth - horizontalInset) + : self->viewportWidth; self->currentTextBlock->layoutAndExtractLines( - self->renderer, self->fontId, self->viewportWidth, + self->renderer, self->fontId, effectiveWidth, [self](const std::shared_ptr& textBlock) { self->addLineToPage(textBlock); }, false); } } @@ -1020,6 +1024,11 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr line) { const int lineHeight = renderer.getLineHeight(fontId) * lineCompression; + if (!currentPage) { + currentPage.reset(new Page()); + currentPageNextY = 0; + } + if (currentPageNextY + lineHeight > viewportHeight) { completePageFn(std::move(currentPage)); completedPageCount++;