Check for cycles in CountNamesInternal().

Prevent infinite loops in name tree objects that reference themselves.

Bug: pdfium:1838
Change-Id: I4ec399f2b3b16d33b729a600e18627f75eec9477
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/94311
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp
index 58a2371..bfcc267 100644
--- a/core/fpdfdoc/cpdf_nametree.cpp
+++ b/core/fpdfdoc/cpdf_nametree.cpp
@@ -6,6 +6,7 @@
 
 #include "core/fpdfdoc/cpdf_nametree.h"
 
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -319,10 +320,16 @@
 }
 
 // Get the total number of key-value pairs in the tree with root |pNode|.
-size_t CountNamesInternal(const CPDF_Dictionary* pNode, int nLevel) {
+size_t CountNamesInternal(const CPDF_Dictionary* pNode,
+                          int nLevel,
+                          std::set<const CPDF_Dictionary*>& seen) {
   if (nLevel > kNameTreeMaxRecursion)
     return 0;
 
+  const bool inserted = seen.insert(pNode).second;
+  if (!inserted)
+    return 0;
+
   const CPDF_Array* pNames = pNode->GetArrayFor("Names");
   if (pNames)
     return pNames->size() / 2;
@@ -337,7 +344,7 @@
     if (!pKid)
       continue;
 
-    nCount += CountNamesInternal(pKid, nLevel + 1);
+    nCount += CountNamesInternal(pKid, nLevel + 1, seen);
   }
   return nCount;
 }
@@ -434,7 +441,8 @@
 }
 
 size_t CPDF_NameTree::GetCount() const {
-  return CountNamesInternal(m_pRoot.Get(), 0);
+  std::set<const CPDF_Dictionary*> seen;
+  return CountNamesInternal(m_pRoot.Get(), 0, seen);
 }
 
 bool CPDF_NameTree::AddValueAndName(RetainPtr<CPDF_Object> pObj,