Avoid generating PDFs with unreferenced objects

In CPDF_Creator::WriteOldObjs(), check to see if objects have references
to them before writing them out.

Bug: chromium:1428724,pdfium:1409
Change-Id: I4c9d447ab745732909c4f7b5c6061886428a92dd
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/105612
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_creator.cpp b/core/fpdfapi/edit/cpdf_creator.cpp
index 3c9675e..9a2b88b 100644
--- a/core/fpdfapi/edit/cpdf_creator.cpp
+++ b/core/fpdfapi/edit/cpdf_creator.cpp
@@ -9,6 +9,7 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <set>
 #include <utility>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
@@ -22,6 +23,7 @@
 #include "core/fpdfapi/parser/cpdf_security_handler.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
+#include "core/fpdfapi/parser/object_tree_traversal_util.h"
 #include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_random.h"
@@ -163,13 +165,30 @@
 }
 
 bool CPDF_Creator::WriteOldObjs() {
-  uint32_t nLastObjNum = m_pParser->GetLastObjNum();
-  if (!m_pParser->IsValidObjectNumber(nLastObjNum))
+  const uint32_t nLastObjNum = m_pParser->GetLastObjNum();
+  if (!m_pParser->IsValidObjectNumber(nLastObjNum)) {
     return true;
+  }
+  if (m_CurObjNum > nLastObjNum) {
+    return true;
+  }
 
+  const std::set<uint32_t> objects_with_refs =
+      GetObjectsWithReferences(m_pDocument);
+  uint32_t last_object_number_written = 0;
   for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) {
-    if (!WriteOldIndirectObject(objnum))
+    if (!pdfium::Contains(objects_with_refs, objnum)) {
+      continue;
+    }
+    if (!WriteOldIndirectObject(objnum)) {
       return false;
+    }
+    last_object_number_written = objnum;
+  }
+  // If there are no new objects to write, then adjust `m_dwLastObjNum` if
+  // needed to reflect the actual last object number.
+  if (m_NewObjNumArray.empty()) {
+    m_dwLastObjNum = last_object_number_written;
   }
   return true;
 }
diff --git a/fpdfsdk/fpdf_save_embeddertest.cpp b/fpdfsdk/fpdf_save_embeddertest.cpp
index 1289a1f..c18566a 100644
--- a/fpdfsdk/fpdf_save_embeddertest.cpp
+++ b/fpdfsdk/fpdf_save_embeddertest.cpp
@@ -113,12 +113,12 @@
   EXPECT_THAT(GetString(), StartsWith("%PDF-1.6\r\n"));
   EXPECT_THAT(GetString(), HasSubstr("/Root "));
   EXPECT_THAT(GetString(), HasSubstr("/Info "));
-  EXPECT_THAT(GetString(), HasSubstr("/Size 38"));
+  EXPECT_THAT(GetString(), HasSubstr("/Size 37"));
   EXPECT_THAT(GetString(), HasSubstr("35 0 obj"));
   EXPECT_THAT(GetString(), HasSubstr("36 0 obj"));
-  EXPECT_THAT(GetString(), HasSubstr("37 0 obj"));
+  EXPECT_THAT(GetString(), Not(HasSubstr("37 0 obj")));
   EXPECT_THAT(GetString(), Not(HasSubstr("38 0 obj")));
-  EXPECT_EQ(8219u, GetString().size());
+  EXPECT_EQ(7908u, GetString().size());
 
   // Make sure new document renders the same as the old one.
   ASSERT_TRUE(OpenSavedDocument());