poppler/PDFDoc.cc | 63 +++++++++++++++++++++++++++++++++++++++++------------- poppler/PDFDoc.h | 6 ++--- poppler/XRef.cc | 11 +++++++-- poppler/XRef.h | 4 +-- 4 files changed, 62 insertions(+), 22 deletions(-)
New commits: commit 8677500399fc2548fa816b619580c2c07915a98c Author: Albert Astals Cid <[email protected]> Date: Fri Jul 29 23:28:35 2022 +0200 pdfseparate: Account for XRef::add failing because we run out of memory Fixes #1278 diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index d9162de8..f2a48fd7 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -906,7 +906,14 @@ int PDFDoc::savePageAs(const GooString &name, int pageNo) if (resourcesObj.isDict()) { markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); } - markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2); + if (!markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2)) { + fclose(f); + delete yRef; + delete countRef; + delete outStr; + error(errSyntaxError, -1, "markPageObjects failed"); + return errDamaged; + } Dict *pageDict = page.getDict(); if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) { @@ -1637,7 +1644,7 @@ void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) outStr->printf("%%%c%c%c%c\n", 0xE2, 0xE3, 0xCF, 0xD3); } -void PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) +bool PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) { bool deleteSet = false; if (!alreadyMarkedDicts) { @@ -1650,7 +1657,7 @@ void PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned in if (deleteSet) { delete alreadyMarkedDicts; } - return; + return true; } else { alreadyMarkedDicts->insert(dict); } @@ -1659,7 +1666,10 @@ void PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned in const char *key = dict->getKey(i); if (strcmp(key, "Annots") != 0) { Object obj1 = dict->getValNF(i).copy(); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + const bool success = markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + if (unlikely(!success)) { + return false; + } } else { Object annotsObj = dict->getValNF(i).copy(); if (!annotsObj.isNull()) { @@ -1671,9 +1681,11 @@ void PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned in if (deleteSet) { delete alreadyMarkedDicts; } + + return true; } -void PDFDoc::markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) +bool PDFDoc::markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) { Array *array; @@ -1682,22 +1694,34 @@ void PDFDoc::markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int nu array = obj->getArray(); for (int i = 0; i < array->getLength(); i++) { Object obj1 = array->getNF(i).copy(); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + const bool success = markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + if (unlikely(!success)) { + return false; + } } break; - case objDict: - markDictionnary(obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - break; + case objDict: { + const bool success = markDictionnary(obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + if (unlikely(!success)) { + return false; + } + } break; case objStream: { Stream *stream = obj->getStream(); - markDictionnary(stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + const bool success = markDictionnary(stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + if (unlikely(!success)) { + return false; + } } break; case objRef: { if (obj->getRef().num + (int)numOffset >= xRef->getNumObjects() || xRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) { if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryFree) { - return; // already marked as free => should be replaced + return true; // already marked as free => should be replaced + } + const bool success = xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, true); + if (unlikely(!success)) { + return false; } - xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, true); if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryCompressed) { xRef->getEntry(obj->getRef().num + numOffset)->type = xrefEntryCompressed; } @@ -1712,11 +1736,16 @@ void PDFDoc::markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int nu } } Object obj1 = getXRef()->fetch(obj->getRef()); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); + const bool success = markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); + if (unlikely(!success)) { + return false; + } } break; default: break; } + + return true; } void PDFDoc::replacePageDict(int pageNo, int rotate, const PDFRectangle *mediaBox, const PDFRectangle *cropBox) @@ -1754,7 +1783,7 @@ void PDFDoc::replacePageDict(int pageNo, int rotate, const PDFRectangle *mediaBo getXRef()->setModifiedObject(&page, *refPage); } -void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) +bool PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts) { pageDict->remove("OpenAction"); pageDict->remove("Outlines"); @@ -1764,9 +1793,13 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigne const char *key = pageDict->getKey(n); Object value = pageDict->getValNF(n).copy(); if (strcmp(key, "Parent") != 0 && strcmp(key, "Pages") != 0 && strcmp(key, "AcroForm") != 0 && strcmp(key, "Annots") != 0 && strcmp(key, "P") != 0 && strcmp(key, "Root") != 0) { - markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + const bool success = markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); + if (unlikely(!success)) { + return false; + } } } + return true; } bool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldPageNum, int newPageNum, std::set<Dict *> *alreadyMarkedDicts) diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 040878cd..b3f5f4ea 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -318,7 +318,7 @@ public: // rewrite pageDict with MediaBox, CropBox and new page CTM void replacePageDict(int pageNo, int rotate, const PDFRectangle *mediaBox, const PDFRectangle *cropBox); - void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts = nullptr); + bool markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts = nullptr); bool markAnnotations(Object *annots, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldPageNum, int newPageNum, std::set<Dict *> *alreadyMarkedDicts = nullptr); void markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum); // write all objects used by pageDict to outStr @@ -343,8 +343,8 @@ public: private: // insert referenced objects in XRef - void markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts); - void markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts = nullptr); + bool markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts); + bool markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts = nullptr); static void writeDictionnary(Dict *dict, OutStream *outStr, XRef *xRef, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref, std::set<Dict *> *alreadyWrittenDicts); // Write object header to current file stream and return its offset diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 9de4edd4..601ecd6a 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1380,12 +1380,18 @@ void XRef::add(Ref ref, Goffset offs, bool used) add(ref.num, ref.gen, offs, used); } -void XRef::add(int num, int gen, Goffset offs, bool used) +bool XRef::add(int num, int gen, Goffset offs, bool used) { xrefLocker(); if (num >= size) { if (num >= capacity) { - entries = (XRefEntry *)greallocn(entries, num + 1, sizeof(XRefEntry)); + entries = (XRefEntry *)greallocn_checkoverflow(entries, num + 1, sizeof(XRefEntry)); + if (unlikely(entries == nullptr)) { + size = 0; + capacity = 0; + return false; + } + capacity = num + 1; } for (int i = size; i < num + 1; ++i) { @@ -1408,6 +1414,7 @@ void XRef::add(int num, int gen, Goffset offs, bool used) e->type = xrefEntryFree; e->offset = 0; } + return true; } void XRef::setModifiedObject(const Object *o, Ref r) diff --git a/poppler/XRef.h b/poppler/XRef.h index 05fce5b9..e2b2ca8f 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -14,7 +14,7 @@ // under GPL version 2 or later // // Copyright (C) 2005 Brad Hards <[email protected]> -// Copyright (C) 2006, 2008, 2010-2013, 2017-2021 Albert Astals Cid <[email protected]> +// Copyright (C) 2006, 2008, 2010-2013, 2017-2022 Albert Astals Cid <[email protected]> // Copyright (C) 2007-2008 Julien Rebetez <[email protected]> // Copyright (C) 2007 Carlos Garcia Campos <[email protected]> // Copyright (C) 2010 Ilya Gorenbein <[email protected]> @@ -207,7 +207,7 @@ public: void setModifiedObject(const Object *o, Ref r); Ref addIndirectObject(const Object &o); void removeIndirectObject(Ref r); - void add(int num, int gen, Goffset offs, bool used); + bool add(int num, int gen, Goffset offs, bool used); void add(Ref ref, Goffset offs, bool used); // Adds a stream object using AutoFreeMemStream. // The function takes ownership over dict and buffer.
