Check for repeated pages in CPDF_DataAvail::GetPageKids().

Page objects can form cycles. Detect and avoid them.

Bug: chromium:1201087
Change-Id: I00c7374f406de8e561a81f037f55101042695f21
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/80150
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index 8f59630..e743483 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -24,6 +24,7 @@
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
+#include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_safe_types.h"
 #include "third_party/base/check.h"
@@ -104,6 +105,8 @@
   if (!m_dwFileLen)
     return DataError;
 
+  DCHECK(m_SeenPageObjList.empty());
+  AutoRestorer<std::set<uint32_t>> seen_objects_restorer(&m_SeenPageObjList);
   const HintsScope hints_scope(GetValidator(), pHints);
   while (!m_bDocAvail) {
     if (!CheckDocStatus())
@@ -346,15 +349,17 @@
   if (!pKids)
     return true;
 
+  std::vector<uint32_t> object_numbers;
   switch (pKids->GetType()) {
     case CPDF_Object::kReference:
-      m_PageObjList.push_back(pKids->AsReference()->GetRefObjNum());
+      object_numbers.push_back(pKids->AsReference()->GetRefObjNum());
       break;
     case CPDF_Object::kArray: {
-      CPDF_Array* pKidsArray = pKids->AsArray();
-      for (size_t i = 0; i < pKidsArray->size(); ++i) {
-        if (CPDF_Reference* pRef = ToReference(pKidsArray->GetObjectAt(i)))
-          m_PageObjList.push_back(pRef->GetRefObjNum());
+      CPDF_ArrayLocker locker(pKids->AsArray());
+      for (const auto& pArrayObj : locker) {
+        CPDF_Reference* pRef = ToReference(pArrayObj.Get());
+        if (pRef)
+          object_numbers.push_back(pRef->GetRefObjNum());
       }
       break;
     }
@@ -362,6 +367,12 @@
       m_docStatus = PDF_DATAAVAIL_ERROR;
       return false;
   }
+
+  for (uint32_t num : object_numbers) {
+    bool inserted = m_SeenPageObjList.insert(num).second;
+    if (inserted)
+      m_PageObjList.push_back(num);
+  }
   return true;
 }
 
diff --git a/core/fpdfapi/parser/cpdf_data_avail.h b/core/fpdfapi/parser/cpdf_data_avail.h
index bbeb987..8dc0394 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.h
+++ b/core/fpdfapi/parser/cpdf_data_avail.h
@@ -178,6 +178,7 @@
   const FX_FILESIZE m_dwFileLen;
   UnownedPtr<CPDF_Document> m_pDocument;
   std::vector<uint32_t> m_PageObjList;
+  std::set<uint32_t> m_SeenPageObjList;
   uint32_t m_PagesObjNum = 0;
   bool m_bLinearedDataOK = false;
   bool m_bMainXRefLoadTried = false;