crashtesting: keep a page that pdfium cannot read in the import

reproduce by converting the crashtesting document
bitmapreadaccess_getpixelforn24bittcbgr_segmentation_fault.sample,
which is a pdf despite its name, to odg:

 soffice.bin: sd/source/filter/pdf/sdpdffilter.cxx:102: bool ImportPDF(...):
 Assertion `nPageNumber >= 0 && o3tl::make_unsigned(nPageNumber) < aGraphics.size()' failed.

pdfium cannot read three of the five pages here. Both the page size by
index and the page itself fail, so this isn't our size test being too
strict. The file is fuzzed, mutool reports a broken xref and an
invalid object number, and one MediaBox reads
[ 1612934155079108773 0 594 841 ].

ImportPDFUnloaded dropped each page that it couldn't read, so a five
page pdf became a two page Draw document with nothing to say three
pages were lost. The graphics that remained kept their own pdf page
numbers, which then had gaps, and the last one pointed past the end.

Keep an entry for every page the pdf declares. Such a page takes the
size of the last page that did come through, A4 to start, and warns.
It still carries its own page number, so there are no gaps left for
sd to trip over.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: Id0d0bde13a2102b4e30cc0dd71edf17031406e1d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5639
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit 321ab2f58f62bf3037ee32e1696bacd14c8f06ed)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211020
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Caolán McNamara
2026-09-16 11:36:37 +02:00
committed by Xisco Fauli
parent 6451dfad11
commit 949b19a363
+23 -13
View File
@@ -425,37 +425,47 @@ ImportPDFUnloaded(SvStream& rStream, std::vector<PDFGraphicResult>& rGraphics,
if (nPageCount <= 0)
return 0;
// A page pdfium cannot read still gets an entry, so the result keeps one page per page the
// pdf declares and every entry knows its own page number. Such a page takes the size of the
// last page that did come through, starting at A4 in 1/100 mm.
Size aLastGoodSize(21000, 29700);
for (int nPageIndex = 0; nPageIndex < nPageCount; ++nPageIndex)
{
basegfx::B2DSize aPageSize = pPdfDocument->getPageSize(nPageIndex);
if (aPageSize.getWidth() <= 0.0 || aPageSize.getHeight() <= 0.0)
continue;
// Returned unit is points
basegfx::B2DSize aPageSize = pPdfDocument->getPageSize(nPageIndex);
std::unique_ptr<vcl::pdf::PDFiumPage> pPage;
if (aPageSize.getWidth() > 0.0 && aPageSize.getHeight() > 0.0)
pPage = pPdfDocument->openPage(nPageIndex);
if (!pPage)
{
SAL_WARN("vcl.filter",
"ImportPDF: page " << nPageIndex << " is unreadable, importing it blank");
rGraphics.emplace_back(Graphic(pGfxLink, nPageIndex), aLastGoodSize,
std::vector<PDFGraphicAnnotation>(),
std::vector<std::pair<basegfx::B2DRectangle, OUString>>());
continue;
}
tools::Long nPageWidth = std::round(convertPointToMm100(aPageSize.getWidth()));
tools::Long nPageHeight = std::round(convertPointToMm100(aPageSize.getHeight()));
aLastGoodSize = Size(nPageWidth, nPageHeight);
// Create the Graphic with the VectorGraphicDataPtr and link the original PDF stream.
// We swap out this Graphic as soon as possible, and a later swap in
// actually renders the correct Bitmap on demand.
Graphic aGraphic(pGfxLink, nPageIndex);
auto pPage = pPdfDocument->openPage(nPageIndex);
if (!pPage)
{
SAL_WARN("vcl.filter", "ImportPDF: unable to open page: " << nPageIndex);
continue;
}
std::vector<PDFGraphicAnnotation> aPDFGraphicAnnotations
= findAnnotations(pPage, aPageSize);
std::vector<std::pair<basegfx::B2DRectangle, OUString>> aPDFLinksInfo
= findLinks(pPage, pPdfDocument, aPageSize);
rGraphics.emplace_back(std::move(aGraphic), Size(nPageWidth, nPageHeight),
aPDFGraphicAnnotations, aPDFLinksInfo);
rGraphics.emplace_back(std::move(aGraphic), aLastGoodSize, aPDFGraphicAnnotations,
aPDFLinksInfo);
}
return rGraphics.size();