Index: core/fpdfapi/parser/cpdf_object_unittest.cpp |
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp |
index b2177afd8afae08a5555944d542ad6fa0f83ebb0..657f536c2656d90074bf5c41911e87cecb42f1e7 100644 |
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp |
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp |
@@ -25,6 +25,7 @@ namespace { |
using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>; |
using ScopedDict = |
std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>; |
+using ScopedStream = std::unique_ptr<CPDF_Stream, ReleaseDeleter<CPDF_Stream>>; |
void TestArrayAccessors(const CPDF_Array* arr, |
size_t index, |
@@ -95,8 +96,10 @@ class PDFObjectsTest : public testing::Test { |
// Indirect references to indirect objects. |
m_ObjHolder.reset(new CPDF_IndirectObjectHolder()); |
- m_IndirectObjs = {boolean_true_obj, number_int_obj, str_spec_obj, name_obj, |
- m_ArrayObj, m_DictObj, stream_obj}; |
+ m_IndirectObjs = {boolean_true_obj->Clone(), number_int_obj->Clone(), |
+ str_spec_obj->Clone(), name_obj->Clone(), |
+ m_ArrayObj->Clone(), m_DictObj->Clone(), |
+ stream_obj->Clone()}; |
for (size_t i = 0; i < m_IndirectObjs.size(); ++i) { |
m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]); |
m_RefObjs.emplace_back(new CPDF_Reference( |
@@ -104,7 +107,7 @@ class PDFObjectsTest : public testing::Test { |
} |
} |
- bool Equal(CPDF_Object* obj1, CPDF_Object* obj2) { |
+ bool Equal(const CPDF_Object* obj1, const CPDF_Object* obj2) { |
if (obj1 == obj2) |
return true; |
if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType()) |
@@ -253,7 +256,7 @@ TEST_F(PDFObjectsTest, GetDict) { |
const CPDF_Dictionary* const indirect_obj_results[] = { |
nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; |
for (size_t i = 0; i < m_RefObjs.size(); ++i) |
- EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetDict()); |
+ EXPECT_TRUE(Equal(indirect_obj_results[i], m_RefObjs[i]->GetDict())); |
} |
TEST_F(PDFObjectsTest, GetArray) { |
@@ -787,10 +790,9 @@ TEST(PDFDictionaryTest, CloneDirectObject) { |
TEST(PDFObjectTest, CloneCheckLoop) { |
{ |
- // Create an object with a reference loop. |
- ScopedArray arr_obj(new CPDF_Array); |
- // Dictionary object. |
+ // Create a dictionary/array pair with a reference loop. |
CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); |
+ ScopedArray arr_obj(new CPDF_Array); |
dict_obj->SetFor("arr", arr_obj.get()); |
arr_obj->InsertAt(0, dict_obj); |
@@ -806,6 +808,22 @@ TEST(PDFObjectTest, CloneCheckLoop) { |
EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); |
} |
{ |
+ // Create a dictionary/stream pair with a reference loop. |
+ CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); |
+ ScopedStream stream_obj(new CPDF_Stream(nullptr, 0, dict_obj)); |
+ dict_obj->SetFor("stream", stream_obj.get()); |
+ |
+ // Clone this object to see whether stack overflow will be triggered. |
+ ScopedStream cloned_stream(stream_obj->Clone()->AsStream()); |
+ // Cloned object should be the same as the original. |
+ ASSERT_TRUE(cloned_stream); |
+ CPDF_Object* cloned_dict = cloned_stream->GetDict(); |
+ ASSERT_TRUE(cloned_dict); |
+ ASSERT_TRUE(cloned_dict->IsDictionary()); |
+ // Recursively referenced object is not cloned. |
+ EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("stream")); |
+ } |
+ { |
CPDF_IndirectObjectHolder objects_holder; |
// Create an object with a reference loop. |
CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); |