diff options
author | weili <weili@chromium.org> | 2016-08-23 22:08:37 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-08-23 22:08:37 -0700 |
commit | a470b5e5371d0674d06068ec38d0d3c3279e85e1 (patch) | |
tree | e13f893084515082052e30c1cb8d94ec6303e38b /core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp | |
parent | 0dadcc6fdab7ad1f2ee95d763f31aad5d3534f93 (diff) | |
download | pdfium-a470b5e5371d0674d06068ec38d0d3c3279e85e1.tar.xz |
Fix stack overflow in object Clone() functions
For some complex objects such as CPDF_Dictionary, CPDF_Array,
CPDF_Stream, and CPDF_Reference, Clone() could be executed with
infinite recursion to cause the stack overflow. Fix this by
checking already cloned objects to avoid recursion.
BUG=pdfium:513
Review-Url: https://codereview.chromium.org/2250533002
Diffstat (limited to 'core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp')
-rw-r--r-- | core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp index 52b01fe3b4..018300d462 100644 --- a/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp +++ b/core/fpdfapi/fpdf_parser/cpdf_object_unittest.cpp @@ -23,6 +23,8 @@ namespace { using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>; +using ScopedDict = + std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>; void TestArrayAccessors(const CPDF_Array* arr, size_t index, @@ -744,3 +746,52 @@ TEST(PDFArrayTest, AddReferenceAndGetObjectAt) { EXPECT_EQ(indirect_objs[i], arr1->GetDirectObjectAt(i)); } } + +TEST(PDFObjectTest, CloneCheckLoop) { + { + // Create an object with a reference loop. + ScopedArray arr_obj(new CPDF_Array); + // Dictionary object. + CPDF_Dictionary* dict_obj = new CPDF_Dictionary; + dict_obj->SetAt("arr", arr_obj.get()); + arr_obj->InsertAt(0, dict_obj); + + // Clone this object to see whether stack overflow will be triggered. + ScopedArray cloned_array(arr_obj->Clone()->AsArray()); + // Cloned object should be the same as the original. + ASSERT_TRUE(cloned_array); + EXPECT_EQ(1u, cloned_array->GetCount()); + CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); + ASSERT_TRUE(cloned_dict); + ASSERT_TRUE(cloned_dict->IsDictionary()); + // Recursively referenced object is not cloned. + EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectBy("arr")); + } + { + std::unique_ptr<CPDF_IndirectObjectHolder> m_ObjHolder( + new CPDF_IndirectObjectHolder(nullptr)); + // Create an object with a reference loop. + CPDF_Dictionary* dict_obj = new CPDF_Dictionary; + CPDF_Array* arr_obj = new CPDF_Array; + m_ObjHolder->AddIndirectObject(dict_obj); + EXPECT_EQ(1u, dict_obj->GetObjNum()); + dict_obj->SetAt("arr", arr_obj); + arr_obj->InsertAt(0, dict_obj, m_ObjHolder.get()); + CPDF_Object* elem0 = arr_obj->GetObjectAt(0); + ASSERT_TRUE(elem0); + ASSERT_TRUE(elem0->IsReference()); + EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); + EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); + + // Clone this object to see whether stack overflow will be triggered. + ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); + // Cloned object should be the same as the original. + ASSERT_TRUE(cloned_dict); + CPDF_Object* cloned_arr = cloned_dict->GetObjectBy("arr"); + ASSERT_TRUE(cloned_arr); + ASSERT_TRUE(cloned_arr->IsArray()); + EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); + // Recursively referenced object is not cloned. + EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); + } +} |