Blob Blame History Raw
diff -up qpdf-6.0.0/include/qpdf/QPDF.hh.detect-recursions qpdf-6.0.0/include/qpdf/QPDF.hh
--- qpdf-6.0.0/include/qpdf/QPDF.hh.detect-recursions	2017-08-10 13:39:58.361068939 +0200
+++ qpdf-6.0.0/include/qpdf/QPDF.hh	2017-08-10 13:44:51.610688987 +0200
@@ -603,6 +603,25 @@ class QPDF
         int gen;
     };
 
+    class ResolveRecorder
+    {
+      public:
+        ResolveRecorder(QPDF* qpdf, QPDFObjGen const& og) :
+            qpdf(qpdf),
+            og(og)
+        {
+            qpdf->resolving.insert(og);
+        }
+        virtual ~ResolveRecorder()
+        {
+            this->qpdf->resolving.erase(og);
+        }
+      private:
+        QPDF* qpdf;
+        QPDFObjGen og;
+    };
+    friend class ResolveRecorder;
+   
     void parse(char const* password);
     void warn(QPDFExc const& e);
     void setTrailer(QPDFObjectHandle obj);
@@ -1065,6 +1084,7 @@ class QPDF
     std::map<QPDFObjGen, QPDFXRefEntry> xref_table;
     std::set<int> deleted_objects;
     std::map<QPDFObjGen, ObjCache> obj_cache;
+    std::set<QPDFObjGen> resolving;
     QPDFObjectHandle trailer;
     std::vector<QPDFObjectHandle> all_pages;
     std::map<QPDFObjGen, int> pageobj_to_pages_pos;
diff -up qpdf-6.0.0/libqpdf/QPDF.cc.detect-recursions qpdf-6.0.0/libqpdf/QPDF.cc
--- qpdf-6.0.0/libqpdf/QPDF.cc.detect-recursions	2017-08-10 13:40:01.265045371 +0200
+++ qpdf-6.0.0/libqpdf/QPDF.cc	2017-08-10 13:47:21.742475258 +0200
@@ -1453,7 +1453,21 @@ QPDF::resolve(int objid, int generation)
     // to insert things into the object cache that don't actually
     // exist in the file.
     QPDFObjGen og(objid, generation);
-    if (! this->obj_cache.count(og))
+    if (this->resolving.count(og))
+    {
+        // This can happen if an object references itself directly or
+        // indirectly in some key that has to be resolved during
+        // object parsing, such as stream length.
+       warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
+		        "", this->file->getLastOffset(),
+		        "loop detected resolving object " +
+		        QUtil::int_to_string(objid) + " " +
+		        QUtil::int_to_string(generation)));
+        return new QPDF_Null;
+    }
+    ResolveRecorder rr(this, og);
+
+   if (! this->obj_cache.count(og))
     {
 	if (! this->xref_table.count(og))
 	{