Prevent FPDFAvail_IsDocAvail() from infinite looping.

BUG=pdfium:875

Change-Id: I3cc29990f0a3398ae903bc14417ec695cca30c6c
Reviewed-on: https://pdfium-review.googlesource.com/12391
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Art Snake <art-snake@yandex-team.ru>
Reviewed-by: Wei Li <weili@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index 76190fa..b7ea238 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -943,8 +943,9 @@
     return true;
   }
 
+  // Prevent infinite-looping between Prev entries.
   uint32_t xrefpos = GetDirectInteger(pTrailerDict, "Prev");
-  if (!xrefpos) {
+  if (!xrefpos || !m_SeenPrevPositions.insert(xrefpos).second) {
     m_dwPrevXRefOffset = 0;
     m_docStatus = PDF_DATAAVAIL_LOADALLCROSSREF;
     return true;
diff --git a/core/fpdfapi/parser/cpdf_data_avail.h b/core/fpdfapi/parser/cpdf_data_avail.h
index 1fcdaf0..e2a4a20 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.h
+++ b/core/fpdfapi/parser/cpdf_data_avail.h
@@ -230,6 +230,7 @@
   PageNode m_PageNode;
   std::set<uint32_t> m_pageMapCheckState;
   std::set<uint32_t> m_pagesLoadState;
+  std::set<uint32_t> m_SeenPrevPositions;
   std::unique_ptr<CPDF_HintTables> m_pHintTables;
   bool m_bSupportHintTable;
 };
diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp
index 0e478b4..8576104 100644
--- a/fpdfsdk/fpdfview_embeddertest.cpp
+++ b/fpdfsdk/fpdfview_embeddertest.cpp
@@ -318,6 +318,13 @@
 // reference loop. Cross references will be rebuilt successfully.
 TEST_F(FPDFViewEmbeddertest, CrossRefV4Loop) {
   EXPECT_TRUE(OpenDocument("bug_xrefv4_loop.pdf"));
+
+  // Make sure calling FPDFAvail_IsDocAvail() on this file does not infinite
+  // loop either. See bug 875.
+  int ret = PDF_DATA_NOTAVAIL;
+  while (ret == PDF_DATA_NOTAVAIL)
+    ret = FPDFAvail_IsDocAvail(avail_, &hints_);
+  EXPECT_EQ(PDF_DATA_AVAIL, ret);
 }
 
 // The test should pass when circular references to ParseIndirectObject will not