[poppler] poppler/PDFDoc.cc poppler/PDFDoc.h poppler/XRef.cc poppler/XRef.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jul 29 21:32:23 UTC 2022


 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 <aacid at kde.org>
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 <bradh at frogmouth.net>
-// Copyright (C) 2006, 2008, 2010-2013, 2017-2021 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2006, 2008, 2010-2013, 2017-2022 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2007-2008 Julien Rebetez <julienr at svn.gnome.org>
 // Copyright (C) 2007 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2010 Ilya Gorenbein <igorenbein at finjan.com>
@@ -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.


More information about the poppler mailing list