| OLD | NEW | 
|---|
| 1 // Copyright 2016 PDFium Authors. All rights reserved. | 1 // Copyright 2016 PDFium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" | 5 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" | 
| 6 #include "core/fpdfapi/fpdf_parser/cpdf_null.h" | 6 #include "core/fpdfapi/fpdf_parser/cpdf_null.h" | 
| 7 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | 7 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | 
| 8 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" | 8 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" | 
| 9 #include "core/fpdfapi/fpdf_parser/include/cpdf_name.h" | 9 #include "core/fpdfapi/fpdf_parser/include/cpdf_name.h" | 
| 10 #include "core/fpdfapi/fpdf_parser/include/cpdf_number.h" | 10 #include "core/fpdfapi/fpdf_parser/include/cpdf_number.h" | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 60     CPDF_String* str_reg_obj = new CPDF_String(L"A simple test"); | 60     CPDF_String* str_reg_obj = new CPDF_String(L"A simple test"); | 
| 61     CPDF_String* str_spec_obj = new CPDF_String(L"\t\n"); | 61     CPDF_String* str_spec_obj = new CPDF_String(L"\t\n"); | 
| 62     // Name object. | 62     // Name object. | 
| 63     CPDF_Name* name_obj = new CPDF_Name("space"); | 63     CPDF_Name* name_obj = new CPDF_Name("space"); | 
| 64     // Array object. | 64     // Array object. | 
| 65     m_ArrayObj = new CPDF_Array; | 65     m_ArrayObj = new CPDF_Array; | 
| 66     m_ArrayObj->InsertAt(0, new CPDF_Number(8902)); | 66     m_ArrayObj->InsertAt(0, new CPDF_Number(8902)); | 
| 67     m_ArrayObj->InsertAt(1, new CPDF_Name("address")); | 67     m_ArrayObj->InsertAt(1, new CPDF_Name("address")); | 
| 68     // Dictionary object. | 68     // Dictionary object. | 
| 69     m_DictObj = new CPDF_Dictionary; | 69     m_DictObj = new CPDF_Dictionary; | 
| 70     m_DictObj->SetAt("bool", new CPDF_Boolean(false)); | 70     m_DictObj->SetFor("bool", new CPDF_Boolean(false)); | 
| 71     m_DictObj->SetAt("num", new CPDF_Number(0.23f)); | 71     m_DictObj->SetFor("num", new CPDF_Number(0.23f)); | 
| 72     // Stream object. | 72     // Stream object. | 
| 73     const char content[] = "abcdefghijklmnopqrstuvwxyz"; | 73     const char content[] = "abcdefghijklmnopqrstuvwxyz"; | 
| 74     size_t buf_len = FX_ArraySize(content); | 74     size_t buf_len = FX_ArraySize(content); | 
| 75     uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_len)); | 75     uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_len)); | 
| 76     memcpy(buf, content, buf_len); | 76     memcpy(buf, content, buf_len); | 
| 77     m_StreamDictObj = new CPDF_Dictionary; | 77     m_StreamDictObj = new CPDF_Dictionary; | 
| 78     m_StreamDictObj->SetAt("key1", new CPDF_String(L" test dict")); | 78     m_StreamDictObj->SetFor("key1", new CPDF_String(L" test dict")); | 
| 79     m_StreamDictObj->SetAt("key2", new CPDF_Number(-1)); | 79     m_StreamDictObj->SetFor("key2", new CPDF_Number(-1)); | 
| 80     CPDF_Stream* stream_obj = new CPDF_Stream(buf, buf_len, m_StreamDictObj); | 80     CPDF_Stream* stream_obj = new CPDF_Stream(buf, buf_len, m_StreamDictObj); | 
| 81     // Null Object. | 81     // Null Object. | 
| 82     CPDF_Null* null_obj = new CPDF_Null; | 82     CPDF_Null* null_obj = new CPDF_Null; | 
| 83     // All direct objects. | 83     // All direct objects. | 
| 84     CPDF_Object* objs[] = {boolean_false_obj, boolean_true_obj, number_int_obj, | 84     CPDF_Object* objs[] = {boolean_false_obj, boolean_true_obj, number_int_obj, | 
| 85                            number_float_obj,  str_reg_obj,      str_spec_obj, | 85                            number_float_obj,  str_reg_obj,      str_spec_obj, | 
| 86                            name_obj,          m_ArrayObj,       m_DictObj, | 86                            name_obj,          m_ArrayObj,       m_DictObj, | 
| 87                            stream_obj,        null_obj}; | 87                            stream_obj,        null_obj}; | 
| 88     m_DirectObjTypes = { | 88     m_DirectObjTypes = { | 
| 89         CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER, | 89         CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER, | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 129         } | 129         } | 
| 130         return true; | 130         return true; | 
| 131       } | 131       } | 
| 132       case CPDF_Object::DICTIONARY: { | 132       case CPDF_Object::DICTIONARY: { | 
| 133         const CPDF_Dictionary* dict1 = obj1->AsDictionary(); | 133         const CPDF_Dictionary* dict1 = obj1->AsDictionary(); | 
| 134         const CPDF_Dictionary* dict2 = obj2->AsDictionary(); | 134         const CPDF_Dictionary* dict2 = obj2->AsDictionary(); | 
| 135         if (dict1->GetCount() != dict2->GetCount()) | 135         if (dict1->GetCount() != dict2->GetCount()) | 
| 136           return false; | 136           return false; | 
| 137         for (CPDF_Dictionary::const_iterator it = dict1->begin(); | 137         for (CPDF_Dictionary::const_iterator it = dict1->begin(); | 
| 138              it != dict1->end(); ++it) { | 138              it != dict1->end(); ++it) { | 
| 139           if (!Equal(it->second, dict2->GetObjectBy(it->first))) | 139           if (!Equal(it->second, dict2->GetObjectFor(it->first))) | 
| 140             return false; | 140             return false; | 
| 141         } | 141         } | 
| 142         return true; | 142         return true; | 
| 143       } | 143       } | 
| 144       case CPDF_Object::NULLOBJ: | 144       case CPDF_Object::NULLOBJ: | 
| 145         return true; | 145         return true; | 
| 146       case CPDF_Object::STREAM: { | 146       case CPDF_Object::STREAM: { | 
| 147         const CPDF_Stream* stream1 = obj1->AsStream(); | 147         const CPDF_Stream* stream1 = obj1->AsStream(); | 
| 148         const CPDF_Stream* stream2 = obj2->AsStream(); | 148         const CPDF_Stream* stream2 = obj2->AsStream(); | 
| 149         if (!stream1->GetDict() && !stream2->GetDict()) | 149         if (!stream1->GetDict() && !stream2->GetDict()) | 
| (...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 552     // Dictionary array. | 552     // Dictionary array. | 
| 553     CPDF_Dictionary* vals[3]; | 553     CPDF_Dictionary* vals[3]; | 
| 554     ScopedArray arr(new CPDF_Array); | 554     ScopedArray arr(new CPDF_Array); | 
| 555     for (size_t i = 0; i < 3; ++i) { | 555     for (size_t i = 0; i < 3; ++i) { | 
| 556       vals[i] = new CPDF_Dictionary; | 556       vals[i] = new CPDF_Dictionary; | 
| 557       for (size_t j = 0; j < 3; ++j) { | 557       for (size_t j = 0; j < 3; ++j) { | 
| 558         std::string key("key"); | 558         std::string key("key"); | 
| 559         char buf[33]; | 559         char buf[33]; | 
| 560         key.append(FXSYS_itoa(j, buf, 10)); | 560         key.append(FXSYS_itoa(j, buf, 10)); | 
| 561         int value = j + 200; | 561         int value = j + 200; | 
| 562         vals[i]->SetAt(key.c_str(), new CPDF_Number(value)); | 562         vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); | 
| 563       } | 563       } | 
| 564       arr->InsertAt(i, vals[i]); | 564       arr->InsertAt(i, vals[i]); | 
| 565     } | 565     } | 
| 566     for (size_t i = 0; i < 3; ++i) { | 566     for (size_t i = 0; i < 3; ++i) { | 
| 567       TestArrayAccessors(arr.get(), i,  // Array and index. | 567       TestArrayAccessors(arr.get(), i,  // Array and index. | 
| 568                          "",            // String value. | 568                          "",            // String value. | 
| 569                          nullptr,       // Const string value. | 569                          nullptr,       // Const string value. | 
| 570                          0,             // Integer value. | 570                          0,             // Integer value. | 
| 571                          0,             // Float value. | 571                          0,             // Float value. | 
| 572                          nullptr,       // Array value. | 572                          nullptr,       // Array value. | 
| 573                          vals[i],       // Dictionary value. | 573                          vals[i],       // Dictionary value. | 
| 574                          nullptr);      // Stream value. | 574                          nullptr);      // Stream value. | 
| 575     } | 575     } | 
| 576   } | 576   } | 
| 577   { | 577   { | 
| 578     // Stream array. | 578     // Stream array. | 
| 579     CPDF_Dictionary* vals[3]; | 579     CPDF_Dictionary* vals[3]; | 
| 580     CPDF_Stream* stream_vals[3]; | 580     CPDF_Stream* stream_vals[3]; | 
| 581     ScopedArray arr(new CPDF_Array); | 581     ScopedArray arr(new CPDF_Array); | 
| 582     for (size_t i = 0; i < 3; ++i) { | 582     for (size_t i = 0; i < 3; ++i) { | 
| 583       vals[i] = new CPDF_Dictionary; | 583       vals[i] = new CPDF_Dictionary; | 
| 584       for (size_t j = 0; j < 3; ++j) { | 584       for (size_t j = 0; j < 3; ++j) { | 
| 585         std::string key("key"); | 585         std::string key("key"); | 
| 586         char buf[33]; | 586         char buf[33]; | 
| 587         key.append(FXSYS_itoa(j, buf, 10)); | 587         key.append(FXSYS_itoa(j, buf, 10)); | 
| 588         int value = j + 200; | 588         int value = j + 200; | 
| 589         vals[i]->SetAt(key.c_str(), new CPDF_Number(value)); | 589         vals[i]->SetFor(key.c_str(), new CPDF_Number(value)); | 
| 590       } | 590       } | 
| 591       uint8_t content[] = "content: this is a stream"; | 591       uint8_t content[] = "content: this is a stream"; | 
| 592       size_t data_size = FX_ArraySize(content); | 592       size_t data_size = FX_ArraySize(content); | 
| 593       uint8_t* data = reinterpret_cast<uint8_t*>(malloc(data_size)); | 593       uint8_t* data = reinterpret_cast<uint8_t*>(malloc(data_size)); | 
| 594       memcpy(data, content, data_size); | 594       memcpy(data, content, data_size); | 
| 595       stream_vals[i] = new CPDF_Stream(data, data_size, vals[i]); | 595       stream_vals[i] = new CPDF_Stream(data, data_size, vals[i]); | 
| 596       arr->InsertAt(i, stream_vals[i]); | 596       arr->InsertAt(i, stream_vals[i]); | 
| 597     } | 597     } | 
| 598     for (size_t i = 0; i < 3; ++i) { | 598     for (size_t i = 0; i < 3; ++i) { | 
| 599       TestArrayAccessors(arr.get(), i,     // Array and index. | 599       TestArrayAccessors(arr.get(), i,     // Array and index. | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 619     arr->InsertAt(6, new CPDF_String("", false)); | 619     arr->InsertAt(6, new CPDF_String("", false)); | 
| 620     arr->InsertAt(7, new CPDF_String("It is a test!", false)); | 620     arr->InsertAt(7, new CPDF_String("It is a test!", false)); | 
| 621     arr->InsertAt(8, new CPDF_Name("NAME")); | 621     arr->InsertAt(8, new CPDF_Name("NAME")); | 
| 622     arr->InsertAt(9, new CPDF_Name("test")); | 622     arr->InsertAt(9, new CPDF_Name("test")); | 
| 623     arr->InsertAt(10, new CPDF_Null()); | 623     arr->InsertAt(10, new CPDF_Null()); | 
| 624     CPDF_Array* arr_val = new CPDF_Array; | 624     CPDF_Array* arr_val = new CPDF_Array; | 
| 625     arr_val->AddNumber(1); | 625     arr_val->AddNumber(1); | 
| 626     arr_val->AddNumber(2); | 626     arr_val->AddNumber(2); | 
| 627     arr->InsertAt(11, arr_val); | 627     arr->InsertAt(11, arr_val); | 
| 628     CPDF_Dictionary* dict_val = new CPDF_Dictionary; | 628     CPDF_Dictionary* dict_val = new CPDF_Dictionary; | 
| 629     dict_val->SetAt("key1", new CPDF_String("Linda", false)); | 629     dict_val->SetFor("key1", new CPDF_String("Linda", false)); | 
| 630     dict_val->SetAt("key2", new CPDF_String("Zoe", false)); | 630     dict_val->SetFor("key2", new CPDF_String("Zoe", false)); | 
| 631     arr->InsertAt(12, dict_val); | 631     arr->InsertAt(12, dict_val); | 
| 632     CPDF_Dictionary* stream_dict = new CPDF_Dictionary; | 632     CPDF_Dictionary* stream_dict = new CPDF_Dictionary; | 
| 633     stream_dict->SetAt("key1", new CPDF_String("John", false)); | 633     stream_dict->SetFor("key1", new CPDF_String("John", false)); | 
| 634     stream_dict->SetAt("key2", new CPDF_String("King", false)); | 634     stream_dict->SetFor("key2", new CPDF_String("King", false)); | 
| 635     uint8_t data[] = "A stream for test"; | 635     uint8_t data[] = "A stream for test"; | 
| 636     // The data buffer will be owned by stream object, so it needs to be | 636     // The data buffer will be owned by stream object, so it needs to be | 
| 637     // dynamically allocated. | 637     // dynamically allocated. | 
| 638     size_t buf_size = sizeof(data); | 638     size_t buf_size = sizeof(data); | 
| 639     uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_size)); | 639     uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_size)); | 
| 640     memcpy(buf, data, buf_size); | 640     memcpy(buf, data, buf_size); | 
| 641     CPDF_Stream* stream_val = new CPDF_Stream(buf, buf_size, stream_dict); | 641     CPDF_Stream* stream_val = new CPDF_Stream(buf, buf_size, stream_dict); | 
| 642     arr->InsertAt(13, stream_val); | 642     arr->InsertAt(13, stream_val); | 
| 643     const char* const expected_str[] = { | 643     const char* const expected_str[] = { | 
| 644         "true",          "false", "0",    "-1234", "2345", "0.05", "", | 644         "true",          "false", "0",    "-1234", "2345", "0.05", "", | 
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 762 | 762 | 
| 763   ScopedArray cloned_array(cloned_array_object->AsArray()); | 763   ScopedArray cloned_array(cloned_array_object->AsArray()); | 
| 764   ASSERT_EQ(1U, cloned_array->GetCount()); | 764   ASSERT_EQ(1U, cloned_array->GetCount()); | 
| 765   CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0); | 765   CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0); | 
| 766   EXPECT_FALSE(cloned_obj); | 766   EXPECT_FALSE(cloned_obj); | 
| 767 } | 767 } | 
| 768 | 768 | 
| 769 TEST(PDFDictionaryTest, CloneDirectObject) { | 769 TEST(PDFDictionaryTest, CloneDirectObject) { | 
| 770   CPDF_IndirectObjectHolder objects_holder; | 770   CPDF_IndirectObjectHolder objects_holder; | 
| 771   ScopedDict dict(new CPDF_Dictionary); | 771   ScopedDict dict(new CPDF_Dictionary); | 
| 772   dict->SetAtReference("foo", &objects_holder, 1234); | 772   dict->SetReferenceFor("foo", &objects_holder, 1234); | 
| 773   ASSERT_EQ(1U, dict->GetCount()); | 773   ASSERT_EQ(1U, dict->GetCount()); | 
| 774   CPDF_Object* obj = dict->GetObjectBy("foo"); | 774   CPDF_Object* obj = dict->GetObjectFor("foo"); | 
| 775   ASSERT_TRUE(obj); | 775   ASSERT_TRUE(obj); | 
| 776   EXPECT_TRUE(obj->IsReference()); | 776   EXPECT_TRUE(obj->IsReference()); | 
| 777 | 777 | 
| 778   CPDF_Object* cloned_dict_object = dict->CloneDirectObject(); | 778   CPDF_Object* cloned_dict_object = dict->CloneDirectObject(); | 
| 779   ASSERT_TRUE(cloned_dict_object); | 779   ASSERT_TRUE(cloned_dict_object); | 
| 780   ASSERT_TRUE(cloned_dict_object->IsDictionary()); | 780   ASSERT_TRUE(cloned_dict_object->IsDictionary()); | 
| 781 | 781 | 
| 782   ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); | 782   ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); | 
| 783   ASSERT_EQ(1U, cloned_dict->GetCount()); | 783   ASSERT_EQ(1U, cloned_dict->GetCount()); | 
| 784   CPDF_Object* cloned_obj = cloned_dict->GetObjectBy("foo"); | 784   CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); | 
| 785   EXPECT_FALSE(cloned_obj); | 785   EXPECT_FALSE(cloned_obj); | 
| 786 } | 786 } | 
| 787 | 787 | 
| 788 TEST(PDFObjectTest, CloneCheckLoop) { | 788 TEST(PDFObjectTest, CloneCheckLoop) { | 
| 789   { | 789   { | 
| 790     // Create an object with a reference loop. | 790     // Create an object with a reference loop. | 
| 791     ScopedArray arr_obj(new CPDF_Array); | 791     ScopedArray arr_obj(new CPDF_Array); | 
| 792     // Dictionary object. | 792     // Dictionary object. | 
| 793     CPDF_Dictionary* dict_obj = new CPDF_Dictionary; | 793     CPDF_Dictionary* dict_obj = new CPDF_Dictionary; | 
| 794     dict_obj->SetAt("arr", arr_obj.get()); | 794     dict_obj->SetFor("arr", arr_obj.get()); | 
| 795     arr_obj->InsertAt(0, dict_obj); | 795     arr_obj->InsertAt(0, dict_obj); | 
| 796 | 796 | 
| 797     // Clone this object to see whether stack overflow will be triggered. | 797     // Clone this object to see whether stack overflow will be triggered. | 
| 798     ScopedArray cloned_array(arr_obj->Clone()->AsArray()); | 798     ScopedArray cloned_array(arr_obj->Clone()->AsArray()); | 
| 799     // Cloned object should be the same as the original. | 799     // Cloned object should be the same as the original. | 
| 800     ASSERT_TRUE(cloned_array); | 800     ASSERT_TRUE(cloned_array); | 
| 801     EXPECT_EQ(1u, cloned_array->GetCount()); | 801     EXPECT_EQ(1u, cloned_array->GetCount()); | 
| 802     CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); | 802     CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); | 
| 803     ASSERT_TRUE(cloned_dict); | 803     ASSERT_TRUE(cloned_dict); | 
| 804     ASSERT_TRUE(cloned_dict->IsDictionary()); | 804     ASSERT_TRUE(cloned_dict->IsDictionary()); | 
| 805     // Recursively referenced object is not cloned. | 805     // Recursively referenced object is not cloned. | 
| 806     EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectBy("arr")); | 806     EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); | 
| 807   } | 807   } | 
| 808   { | 808   { | 
| 809     CPDF_IndirectObjectHolder objects_holder; | 809     CPDF_IndirectObjectHolder objects_holder; | 
| 810     // Create an object with a reference loop. | 810     // Create an object with a reference loop. | 
| 811     CPDF_Dictionary* dict_obj = new CPDF_Dictionary; | 811     CPDF_Dictionary* dict_obj = new CPDF_Dictionary; | 
| 812     CPDF_Array* arr_obj = new CPDF_Array; | 812     CPDF_Array* arr_obj = new CPDF_Array; | 
| 813     objects_holder.AddIndirectObject(dict_obj); | 813     objects_holder.AddIndirectObject(dict_obj); | 
| 814     EXPECT_EQ(1u, dict_obj->GetObjNum()); | 814     EXPECT_EQ(1u, dict_obj->GetObjNum()); | 
| 815     dict_obj->SetAt("arr", arr_obj); | 815     dict_obj->SetFor("arr", arr_obj); | 
| 816     arr_obj->InsertAt(0, dict_obj, &objects_holder); | 816     arr_obj->InsertAt(0, dict_obj, &objects_holder); | 
| 817     CPDF_Object* elem0 = arr_obj->GetObjectAt(0); | 817     CPDF_Object* elem0 = arr_obj->GetObjectAt(0); | 
| 818     ASSERT_TRUE(elem0); | 818     ASSERT_TRUE(elem0); | 
| 819     ASSERT_TRUE(elem0->IsReference()); | 819     ASSERT_TRUE(elem0->IsReference()); | 
| 820     EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); | 820     EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); | 
| 821     EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); | 821     EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); | 
| 822 | 822 | 
| 823     // Clone this object to see whether stack overflow will be triggered. | 823     // Clone this object to see whether stack overflow will be triggered. | 
| 824     ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); | 824     ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); | 
| 825     // Cloned object should be the same as the original. | 825     // Cloned object should be the same as the original. | 
| 826     ASSERT_TRUE(cloned_dict); | 826     ASSERT_TRUE(cloned_dict); | 
| 827     CPDF_Object* cloned_arr = cloned_dict->GetObjectBy("arr"); | 827     CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); | 
| 828     ASSERT_TRUE(cloned_arr); | 828     ASSERT_TRUE(cloned_arr); | 
| 829     ASSERT_TRUE(cloned_arr->IsArray()); | 829     ASSERT_TRUE(cloned_arr->IsArray()); | 
| 830     EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); | 830     EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); | 
| 831     // Recursively referenced object is not cloned. | 831     // Recursively referenced object is not cloned. | 
| 832     EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); | 832     EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); | 
| 833   } | 833   } | 
| 834 } | 834 } | 
| OLD | NEW | 
|---|