Return retained results from CPDF_ObjectWalker::GetNext()

Static analysis suggests that the last reference to the object
stored as next_object_ may be removed immediately before returning
it from GetNext(). It is unlikely to be reachable in practice,
since other references can't always be deduced by the analysis.

Bug: chromium:1358732
Change-Id: I235ba38c7085b3d6f0d9310b49a3d12b57bbc07a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/97510
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
index 8e4bfa7..69c2ac1 100644
--- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
@@ -230,18 +230,18 @@
 
   struct MayBeSignature {
     const CPDF_Dictionary* parent;
-    CPDF_Object* contents;
+    RetainPtr<CPDF_Object> contents;
   };
 
   std::stack<MayBeSignature> may_be_sign_dictionaries;
   const uint32_t obj_num = object->GetObjNum();
   const uint32_t gen_num = object->GetGenNum();
 
-  CPDF_Object* object_to_decrypt = object.Get();
+  RetainPtr<CPDF_Object> object_to_decrypt = object;
   while (object_to_decrypt) {
-    CPDF_NonConstObjectWalker walker(object_to_decrypt);
+    CPDF_NonConstObjectWalker walker(object_to_decrypt.Get());
     object_to_decrypt = nullptr;
-    while (CPDF_Object* child = walker.GetNext()) {
+    while (RetainPtr<CPDF_Object> child = walker.GetNext()) {
       const CPDF_Dictionary* parent_dict =
           walker.GetParent() ? walker.GetParent()->GetDict() : nullptr;
       if (walker.dictionary_key() == kContentsKey &&
@@ -253,7 +253,7 @@
         // Temporary skip it, to prevent signature corruption.
         // It will be decrypted on next interations, if this is not contents of
         // signature dictionary.
-        may_be_sign_dictionaries.push(MayBeSignature({parent_dict, child}));
+        may_be_sign_dictionaries.push({parent_dict, std::move(child)});
         walker.SkipWalkIntoCurrentObject();
         continue;
       }
diff --git a/core/fpdfapi/parser/cpdf_object_avail.cpp b/core/fpdfapi/parser/cpdf_object_avail.cpp
index c47be27..bad6a16 100644
--- a/core/fpdfapi/parser/cpdf_object_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_object_avail.cpp
@@ -113,14 +113,14 @@
     return true;
 
   CPDF_ObjectWalker walker(object);
-  while (const CPDF_Object* obj = walker.GetNext()) {
+  while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) {
     CPDF_ReadValidator::ScopedSession parse_session(validator_);
 
     // Skip if this object if it's an inlined root, the parent object or
     // explicitily excluded.
     const bool skip = (walker.GetParent() && obj == root_) ||
                       walker.dictionary_key() == "Parent" ||
-                      (obj != root_ && ExcludeObject(obj));
+                      (obj != root_ && ExcludeObject(obj.Get()));
 
     // We need to parse the object before we can do the exclusion check.
     // This is because the exclusion check may check against a referenced
diff --git a/core/fpdfapi/parser/cpdf_object_walker.cpp b/core/fpdfapi/parser/cpdf_object_walker.cpp
index dfebab6..c0551dc 100644
--- a/core/fpdfapi/parser/cpdf_object_walker.cpp
+++ b/core/fpdfapi/parser/cpdf_object_walker.cpp
@@ -132,7 +132,7 @@
 
 CPDF_ObjectWalker::~CPDF_ObjectWalker() = default;
 
-const CPDF_Object* CPDF_ObjectWalker::GetNext() {
+RetainPtr<const CPDF_Object> CPDF_ObjectWalker::GetNext() {
   while (!stack_.empty() || next_object_) {
     if (next_object_) {
       auto new_iterator = MakeIterator(next_object_.Get());
@@ -140,9 +140,7 @@
         // Schedule walk within composite objects.
         stack_.push(std::move(new_iterator));
       }
-      auto* result = next_object_.Get();
-      next_object_ = nullptr;
-      return result;
+      return std::move(next_object_);  // next_object_ now NULL after move.
     }
 
     SubobjectIterator* it = stack_.top().get();
diff --git a/core/fpdfapi/parser/cpdf_object_walker.h b/core/fpdfapi/parser/cpdf_object_walker.h
index 92b51a9..56be755 100644
--- a/core/fpdfapi/parser/cpdf_object_walker.h
+++ b/core/fpdfapi/parser/cpdf_object_walker.h
@@ -39,7 +39,7 @@
   explicit CPDF_ObjectWalker(const CPDF_Object* root);
   ~CPDF_ObjectWalker();
 
-  const CPDF_Object* GetNext();
+  RetainPtr<const CPDF_Object> GetNext();
   void SkipWalkIntoCurrentObject();
 
   size_t current_depth() const { return current_depth_; }
@@ -62,8 +62,9 @@
   explicit CPDF_NonConstObjectWalker(CPDF_Object* root)
       : CPDF_ObjectWalker(root) {}
 
-  CPDF_Object* GetNext() {
-    return const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext());
+  RetainPtr<CPDF_Object> GetNext() {
+    return pdfium::WrapRetain(
+        const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext().Get()));
   }
 };
 
diff --git a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
index 99c575e..4106d0d 100644
--- a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
@@ -24,7 +24,7 @@
 std::string Walk(CPDF_Object* object) {
   std::ostringstream result;
   CPDF_ObjectWalker walker(object);
-  while (const CPDF_Object* obj = walker.GetNext()) {
+  while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) {
     if (obj->IsDictionary())
       result << " Dict";
     else if (obj->IsArray())
@@ -91,9 +91,9 @@
   // We have <</Array [ stream( << /Length 0 >>) ]>>
   // In this case each step will increase depth.
   // And on each step the prev object should be parent for current.
-  const CPDF_Object* cur_parent = nullptr;
+  RetainPtr<const CPDF_Object> cur_parent;
   CPDF_ObjectWalker walker(level_0.Get());
-  while (const CPDF_Object* obj = walker.GetNext()) {
+  while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) {
     EXPECT_EQ(cur_parent, walker.GetParent());
     cur_parent = obj;
   }
@@ -110,7 +110,7 @@
 
   int non_array_objects = 0;
   CPDF_ObjectWalker walker(root_array.Get());
-  while (const CPDF_Object* obj = walker.GetNext()) {
+  while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) {
     if (obj != root_array && obj->IsArray()) {
       // skip other array except root.
       walker.SkipWalkIntoCurrentObject();
@@ -131,7 +131,7 @@
   dict->SetFor("5", pdfium::MakeRetain<CPDF_Null>());
 
   CPDF_ObjectWalker walker(dict.Get());
-  while (const CPDF_Object* obj = walker.GetNext()) {
+  while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) {
     if (dict == obj) {
       // Ignore root dictinary object
       continue;