Merge to XFA: Fix infinite loop caused by parsing same indirect objects

BUG=pdfium:343
TBR=thestig@chromium.org

Review URL: https://codereview.chromium.org/1569343002 .

(cherry picked from commit 149f1db8bba85bdf2b40d330c38f2478695ca0d5)

Review URL: https://codereview.chromium.org/1575663002 .
diff --git a/core/include/fpdfapi/fpdf_parser.h b/core/include/fpdfapi/fpdf_parser.h
index 7568509..e1901eb 100644
--- a/core/include/fpdfapi/fpdf_parser.h
+++ b/core/include/fpdfapi/fpdf_parser.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 
 #include "core/include/fpdfapi/fpdf_objects.h"
 #include "core/include/fxcrt/fx_system.h"
@@ -536,6 +537,9 @@
   // streams in |m_ObjectStreamMap| are valid.
   std::map<CPDF_StreamAcc*, StreamObjectCache> m_ObjCache;
 
+  // All indirect object numbers that are being parsed.
+  std::set<FX_DWORD> m_ParsingObjNums;
+
   friend class CPDF_Creator;
   friend class CPDF_DataAvail;
 };
diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
index ad97d1f..236ecaa 100644
--- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
+++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp
@@ -36,6 +36,20 @@
   FX_DWORD m_Offset;
 };
 
+template <typename T>
+class ScopedSetInsertion {
+ public:
+  ScopedSetInsertion(std::set<T>* org_set, T elem)
+      : m_Set(org_set), m_Entry(elem) {
+    m_Set->insert(m_Entry);
+  }
+  ~ScopedSetInsertion() { m_Set->erase(m_Entry); }
+
+ private:
+  std::set<T>* const m_Set;
+  const T m_Entry;
+};
+
 int CompareFileSize(const void* p1, const void* p2) {
   return *(FX_FILESIZE*)p1 - *(FX_FILESIZE*)p2;
 }
@@ -1193,6 +1207,11 @@
   if (!IsValidObjectNumber(objnum))
     return nullptr;
 
+  // Prevent circular parsing the same object.
+  if (pdfium::ContainsKey(m_ParsingObjNums, objnum))
+    return nullptr;
+  ScopedSetInsertion<FX_DWORD> local_insert(&m_ParsingObjNums, objnum);
+
   if (m_V5Type[objnum] == 1 || m_V5Type[objnum] == 255) {
     FX_FILESIZE pos = m_ObjectInfo[objnum].pos;
     if (pos <= 0)
diff --git a/fpdfsdk/src/fpdfview_embeddertest.cpp b/fpdfsdk/src/fpdfview_embeddertest.cpp
index 6eb5fb9..6a6d076 100644
--- a/fpdfsdk/src/fpdfview_embeddertest.cpp
+++ b/fpdfsdk/src/fpdfview_embeddertest.cpp
@@ -216,3 +216,9 @@
 TEST_F(FPDFViewEmbeddertest, CrossRefV4Loop) {
   EXPECT_TRUE(OpenDocument("bug_xrefv4_loop.pdf"));
 }
+
+// The test should pass when circular references to ParseIndirectObject will not
+// cause infinite loop.
+TEST_F(FPDFViewEmbeddertest, Hang_343) {
+  EXPECT_FALSE(OpenDocument("bug_343.pdf"));
+}
\ No newline at end of file
diff --git a/testing/resources/bug_343.pdf b/testing/resources/bug_343.pdf
new file mode 100644
index 0000000..1ad8387
--- /dev/null
+++ b/testing/resources/bug_343.pdf
@@ -0,0 +1,19 @@
+'%PDF-1.6
+%âãÏÓ
+<<1 0 objParams%PDF-1.4
+tr%PDF-1.2
+%âãÏÓ
+7 0 obj <<
+! /Type /Font
+trailer
+<<//'/OC3
+endob*
+4 0 obj <<
+  /Resources <<
+  /FT 7 0 R
+>>
+endstream
+endobailer/%
+<<Subtj
+%%EOF
+/parenriy[1.0 +-1.0]pe:XM/Leng#th 308/Type/Sig[gh/Metadata>>%stP
\ No newline at end of file