From 32e88c3824f84c4ca48d9c3ef59845107e083e5b Mon Sep 17 00:00:00 2001 From: Victor Gomes Date: Thu, 6 May 2021 20:25:59 +0200 Subject: [PATCH] Reland "[runtime] Add length check in ConvertElementsWithCapacity" This is a reland of b271648e94e5d2acb7f8d4a1dd1f109aa54cc7c4 Unfortunately the test can still throw a fatal error, since there are other possible paths for OOM. Original change's description: > [runtime] Add length check in ConvertElementsWithCapacity > > This also propagates the exception through all the users of > ConvertElementsWithCapacity. > > Bug: chromium:1201626 > Change-Id: Ie44ba4327a4c3a20f1376477f45d3cd95d0da3b3 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2857961 > Commit-Queue: Victor Gomes > Reviewed-by: Toon Verwaest > Cr-Commit-Position: refs/heads/master@{#74412} Bug: chromium:1201626 Change-Id: I164ca1aca21ad6f45ccf8893fb07a47cd5ed079a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2877833 Reviewed-by: Toon Verwaest Commit-Queue: Victor Gomes Cr-Commit-Position: refs/heads/master@{#74433} --- src/builtins/accessors.cc | 7 +- src/builtins/builtins-array.cc | 21 +- src/builtins/builtins-typed-array.cc | 3 +- src/objects/elements.cc | 389 ++++++++++++++++----------- src/objects/elements.h | 37 +-- src/objects/intl-objects.cc | 18 +- src/objects/js-array.h | 4 +- src/objects/js-objects.cc | 20 +- src/objects/js-objects.h | 7 +- src/objects/objects.cc | 11 +- src/objects/value-serializer.cc | 4 +- src/runtime/runtime-array.cc | 15 +- 12 files changed, 327 insertions(+), 209 deletions(-) diff --git a/src/builtins/accessors.cc b/src/builtins/accessors.cc index f4186e5d8d..0285b33e1f 100644 --- a/src/builtins/accessors.cc +++ b/src/builtins/accessors.cc @@ -203,7 +203,12 @@ void Accessors::ArrayLengthSetter( return; } - JSArray::SetLength(array, length); + if (JSArray::SetLength(array, length).IsNothing()) { + // TODO(victorgomes): AccessorNameBooleanSetterCallback does not handle + // exceptions. + FATAL("Fatal JavaScript invalid array length %u", length); + UNREACHABLE(); + } uint32_t actual_new_len = 0; CHECK(array->length().ToArrayLength(&actual_new_len)); diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc index d3bbd980a5..a5dc159db9 100644 --- a/src/builtins/builtins-array.cc +++ b/src/builtins/builtins-array.cc @@ -173,7 +173,8 @@ V8_WARN_UNUSED_RESULT MaybeHandle SetLengthProperty( Handle array = Handle::cast(receiver); if (!JSArray::HasReadOnlyLength(array)) { DCHECK_LE(length, kMaxUInt32); - JSArray::SetLength(array, static_cast(length)); + MAYBE_RETURN_NULL( + JSArray::SetLength(array, static_cast(length))); return receiver; } } @@ -385,7 +386,9 @@ BUILTIN(ArrayPush) { } ElementsAccessor* accessor = array->GetElementsAccessor(); - uint32_t new_length = accessor->Push(array, &args, to_add); + uint32_t new_length; + MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, new_length, accessor->Push(array, &args, to_add)); return *isolate->factory()->NewNumberFromUint((new_length)); } @@ -468,7 +471,8 @@ BUILTIN(ArrayPop) { Handle result; if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { // Fast Elements Path - result = array->GetElementsAccessor()->Pop(array); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, array->GetElementsAccessor()->Pop(array)); } else { // Use Slow Lookup otherwise uint32_t new_length = len - 1; @@ -483,7 +487,9 @@ BUILTIN(ArrayPop) { isolate->factory()->length_string(), Object::TypeOf(isolate, array), array)); } - JSArray::SetLength(array, new_length); + bool set_len_ok; + MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, set_len_ok, JSArray::SetLength(array, new_length)); } return *result; @@ -595,7 +601,8 @@ BUILTIN(ArrayShift) { if (CanUseFastArrayShift(isolate, receiver)) { Handle array = Handle::cast(receiver); - return *array->GetElementsAccessor()->Shift(array); + RETURN_RESULT_OR_FAILURE(isolate, + array->GetElementsAccessor()->Shift(array)); } return GenericArrayShift(isolate, receiver, length); @@ -623,7 +630,9 @@ BUILTIN(ArrayUnshift) { DCHECK(!JSArray::HasReadOnlyLength(array)); ElementsAccessor* accessor = array->GetElementsAccessor(); - int new_length = accessor->Unshift(array, &args, to_add); + uint32_t new_length; + MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, new_length, accessor->Unshift(array, &args, to_add)); return Smi::FromInt(new_length); } diff --git a/src/builtins/builtins-typed-array.cc b/src/builtins/builtins-typed-array.cc index fdadc7a554..bb936e6e46 100644 --- a/src/builtins/builtins-typed-array.cc +++ b/src/builtins/builtins-typed-array.cc @@ -154,7 +154,8 @@ BUILTIN(TypedArrayPrototypeFill) { DCHECK_LE(end, len); DCHECK_LE(count, len); - return ElementsAccessor::ForKind(kind)->Fill(array, obj_value, start, end); + RETURN_RESULT_OR_FAILURE(isolate, ElementsAccessor::ForKind(kind)->Fill( + array, obj_value, start, end)); } BUILTIN(TypedArrayPrototypeIncludes) { diff --git a/src/objects/elements.cc b/src/objects/elements.cc index f8f38f5516..6e8e539ff8 100644 --- a/src/objects/elements.cc +++ b/src/objects/elements.cc @@ -639,57 +639,64 @@ class ElementsAccessorBase : public InternalElementsAccessor { UNREACHABLE(); } - void Add(Handle object, uint32_t index, Handle value, - PropertyAttributes attributes, uint32_t new_capacity) final { - Subclass::AddImpl(object, index, value, attributes, new_capacity); + Maybe Add(Handle object, uint32_t index, Handle value, + PropertyAttributes attributes, uint32_t new_capacity) final { + return Subclass::AddImpl(object, index, value, attributes, new_capacity); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { UNREACHABLE(); } - uint32_t Push(Handle receiver, BuiltinArguments* args, - uint32_t push_size) final { + Maybe Push(Handle receiver, BuiltinArguments* args, + uint32_t push_size) final { return Subclass::PushImpl(receiver, args, push_size); } - static uint32_t PushImpl(Handle receiver, BuiltinArguments* args, - uint32_t push_sized) { + static Maybe PushImpl(Handle receiver, + BuiltinArguments* args, uint32_t push_sized) { UNREACHABLE(); } - uint32_t Unshift(Handle receiver, BuiltinArguments* args, - uint32_t unshift_size) final { + Maybe Unshift(Handle receiver, BuiltinArguments* args, + uint32_t unshift_size) final { return Subclass::UnshiftImpl(receiver, args, unshift_size); } - static uint32_t UnshiftImpl(Handle receiver, BuiltinArguments* args, - uint32_t unshift_size) { + static Maybe UnshiftImpl(Handle receiver, + BuiltinArguments* args, + uint32_t unshift_size) { UNREACHABLE(); } - Handle Pop(Handle receiver) final { + MaybeHandle Pop(Handle receiver) final { return Subclass::PopImpl(receiver); } - static Handle PopImpl(Handle receiver) { UNREACHABLE(); } + static MaybeHandle PopImpl(Handle receiver) { + UNREACHABLE(); + } - Handle Shift(Handle receiver) final { + MaybeHandle Shift(Handle receiver) final { return Subclass::ShiftImpl(receiver); } - static Handle ShiftImpl(Handle receiver) { UNREACHABLE(); } - - void SetLength(Handle array, uint32_t length) final { - Subclass::SetLengthImpl(array->GetIsolate(), array, length, - handle(array->elements(), array->GetIsolate())); + static MaybeHandle ShiftImpl(Handle receiver) { + UNREACHABLE(); } - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + Maybe SetLength(Handle array, uint32_t length) final { + return Subclass::SetLengthImpl( + array->GetIsolate(), array, length, + handle(array->elements(), array->GetIsolate())); + } + + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { DCHECK(!array->SetLengthWouldNormalize(length)); DCHECK(IsFastElementsKind(array->GetElementsKind())); uint32_t old_length = 0; @@ -735,11 +742,13 @@ class ElementsAccessorBase : public InternalElementsAccessor { } else { // Check whether the backing store should be expanded. capacity = std::max(length, JSObject::NewElementsCapacity(capacity)); - Subclass::GrowCapacityAndConvertImpl(array, capacity); + MAYBE_RETURN(Subclass::GrowCapacityAndConvertImpl(array, capacity), + Nothing()); } array->set_length(Smi::FromInt(length)); JSObject::ValidateElements(*array); + return Just(true); } size_t NumberOfElements(JSObject receiver) final { @@ -765,22 +774,40 @@ class ElementsAccessorBase : public InternalElementsAccessor { return Subclass::GetMaxIndex(receiver, elements); } - static Handle ConvertElementsWithCapacity( + static MaybeHandle ConvertElementsWithCapacity( Handle object, Handle old_elements, ElementsKind from_kind, uint32_t capacity) { return ConvertElementsWithCapacity(object, old_elements, from_kind, capacity, 0, 0); } - static Handle ConvertElementsWithCapacity( + static MaybeHandle ConvertElementsWithCapacity( Handle object, Handle old_elements, ElementsKind from_kind, uint32_t capacity, uint32_t src_index, uint32_t dst_index) { Isolate* isolate = object->GetIsolate(); Handle new_elements; + // TODO(victorgomes): Retrieve native context in optimized code + // and remove the fatal errors. if (IsDoubleElementsKind(kind())) { + if (capacity < 0 || capacity > FixedDoubleArray::kMaxLength) { + if (isolate->context().is_null()) { + FATAL("Fatal JavaScript invalid array length"); + UNREACHABLE(); + } + return isolate->Throw(isolate->factory()->NewRangeError( + MessageTemplate::kInvalidArrayLength)); + } new_elements = isolate->factory()->NewFixedDoubleArray(capacity); } else { + if (capacity < 0 || capacity > FixedArray::kMaxLength) { + if (isolate->context().is_null()) { + FATAL("Fatal JavaScript invalid array length"); + UNREACHABLE(); + } + return isolate->Throw(isolate->factory()->NewRangeError( + MessageTemplate::kInvalidArrayLength)); + } new_elements = isolate->factory()->NewFixedArray(capacity); } @@ -793,11 +820,11 @@ class ElementsAccessorBase : public InternalElementsAccessor { from_kind, dst_index, packed_size, kCopyToEndAndInitializeToHole); - return new_elements; + return MaybeHandle(new_elements); } - static void TransitionElementsKindImpl(Handle object, - Handle to_map) { + static Maybe TransitionElementsKindImpl(Handle object, + Handle to_map) { Isolate* isolate = object->GetIsolate(); Handle from_map = handle(object->map(), isolate); ElementsKind from_kind = from_map->elements_kind(); @@ -822,8 +849,12 @@ class ElementsAccessorBase : public InternalElementsAccessor { (IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) || (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind))); uint32_t capacity = static_cast(object->elements().length()); - Handle elements = ConvertElementsWithCapacity( - object, from_elements, from_kind, capacity); + Handle elements; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + object->GetIsolate(), elements, + ConvertElementsWithCapacity(object, from_elements, from_kind, + capacity), + Nothing()); JSObject::SetMapAndElements(object, to_map, elements); } if (FLAG_trace_elements_transitions) { @@ -832,10 +863,11 @@ class ElementsAccessorBase : public InternalElementsAccessor { handle(object->elements(), isolate)); } } + return Just(true); } - static void GrowCapacityAndConvertImpl(Handle object, - uint32_t capacity) { + static Maybe GrowCapacityAndConvertImpl(Handle object, + uint32_t capacity) { ElementsKind from_kind = object->GetElementsKind(); if (IsSmiOrObjectElementsKind(from_kind)) { // Array optimizations rely on the prototype lookups of Array objects @@ -850,15 +882,18 @@ class ElementsAccessorBase : public InternalElementsAccessor { DCHECK(IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(kind()) || IsDictionaryElementsKind(from_kind) || static_cast(old_elements->length()) < capacity); - Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind, - kind(), capacity); + return Subclass::BasicGrowCapacityAndConvertImpl( + object, old_elements, from_kind, kind(), capacity); } - static void BasicGrowCapacityAndConvertImpl( + static Maybe BasicGrowCapacityAndConvertImpl( Handle object, Handle old_elements, ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) { - Handle elements = - ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); + Handle elements; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + object->GetIsolate(), elements, + ConvertElementsWithCapacity(object, old_elements, from_kind, capacity), + Nothing()); if (IsHoleyElementsKind(from_kind)) { to_kind = GetHoleyElementsKind(to_kind); @@ -873,40 +908,45 @@ class ElementsAccessorBase : public InternalElementsAccessor { JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements, to_kind, elements); } + return Just(true); } - void TransitionElementsKind(Handle object, Handle map) final { - Subclass::TransitionElementsKindImpl(object, map); + Maybe TransitionElementsKind(Handle object, + Handle map) final { + return Subclass::TransitionElementsKindImpl(object, map); } - void GrowCapacityAndConvert(Handle object, - uint32_t capacity) final { - Subclass::GrowCapacityAndConvertImpl(object, capacity); + Maybe GrowCapacityAndConvert(Handle object, + uint32_t capacity) final { + return Subclass::GrowCapacityAndConvertImpl(object, capacity); } - bool GrowCapacity(Handle object, uint32_t index) final { + Maybe GrowCapacity(Handle object, uint32_t index) final { // This function is intended to be called from optimized code. We don't // want to trigger lazy deopts there, so refuse to handle cases that would. if (object->map().is_prototype_map() || object->WouldConvertToSlowElements(index)) { - return false; + return Just(false); } Handle old_elements(object->elements(), object->GetIsolate()); uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1); DCHECK(static_cast(old_elements->length()) < new_capacity); - Handle elements = - ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity); + Handle elements; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + object->GetIsolate(), elements, + ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity), + Nothing()); DCHECK_EQ(object->GetElementsKind(), kind()); // Transition through the allocation site as well if present. if (JSObject::UpdateAllocationSite( object, kind())) { - return false; + return Just(false); } object->set_elements(*elements); - return true; + return Just(true); } void Delete(Handle obj, InternalIndex entry) final { @@ -1220,13 +1260,14 @@ class ElementsAccessorBase : public InternalElementsAccessor { return Subclass::GetCapacityImpl(holder, backing_store); } - static Object FillImpl(Handle receiver, Handle obj_value, - size_t start, size_t end) { + static MaybeHandle FillImpl(Handle receiver, + Handle obj_value, size_t start, + size_t end) { UNREACHABLE(); } - Object Fill(Handle receiver, Handle obj_value, size_t start, - size_t end) override { + MaybeHandle Fill(Handle receiver, Handle obj_value, + size_t start, size_t end) override { return Subclass::FillImpl(receiver, obj_value, start, end); } @@ -1348,9 +1389,9 @@ class DictionaryElementsAccessor return dict.NumberOfElements(); } - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { Handle dict = Handle::cast(backing_store); uint32_t old_length = 0; @@ -1401,6 +1442,7 @@ class DictionaryElementsAccessor Handle length_obj = isolate->factory()->NewNumberFromUint(length); array->set_length(*length_obj); + return Just(true); } static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from, @@ -1466,9 +1508,10 @@ class DictionaryElementsAccessor dictionary.DetailsAtPut(entry, details); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { PropertyDetails details(kData, attributes, PropertyCellType::kNoCell); Handle dictionary = object->HasFastElements() || object->HasFastStringWrapperElements() @@ -1479,8 +1522,9 @@ class DictionaryElementsAccessor object->GetIsolate(), dictionary, index, value, details); new_dictionary->UpdateMaxNumberKey(index, object); if (attributes != NONE) object->RequireSlowElements(*new_dictionary); - if (dictionary.is_identical_to(new_dictionary)) return; + if (dictionary.is_identical_to(new_dictionary)) return Just(true); object->set_elements(*new_dictionary); + return Just(true); } static bool HasEntryImpl(Isolate* isolate, FixedArrayBase store, @@ -1969,9 +2013,10 @@ class FastElementsAccessor : public ElementsAccessorBase { value, attributes); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { DCHECK_EQ(NONE, attributes); ElementsKind from_kind = object->GetElementsKind(); ElementsKind to_kind = Subclass::kind(); @@ -1979,7 +2024,8 @@ class FastElementsAccessor : public ElementsAccessorBase { IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind) || Subclass::GetCapacityImpl(*object, object->elements()) != new_capacity) { - Subclass::GrowCapacityAndConvertImpl(object, new_capacity); + MAYBE_RETURN(Subclass::GrowCapacityAndConvertImpl(object, new_capacity), + Nothing()); } else { if (IsFastElementsKind(from_kind) && from_kind != to_kind) { JSObject::TransitionElementsKind(object, to_kind); @@ -1990,6 +2036,7 @@ class FastElementsAccessor : public ElementsAccessorBase { } } Subclass::SetImpl(object, InternalIndex(index), *value); + return Just(true); } static void DeleteImpl(Handle obj, InternalIndex entry) { @@ -2084,24 +2131,25 @@ class FastElementsAccessor : public ElementsAccessorBase { #endif } - static Handle PopImpl(Handle receiver) { + static MaybeHandle PopImpl(Handle receiver) { return Subclass::RemoveElement(receiver, AT_END); } - static Handle ShiftImpl(Handle receiver) { + static MaybeHandle ShiftImpl(Handle receiver) { return Subclass::RemoveElement(receiver, AT_START); } - static uint32_t PushImpl(Handle receiver, BuiltinArguments* args, - uint32_t push_size) { + static Maybe PushImpl(Handle receiver, + BuiltinArguments* args, uint32_t push_size) { Handle backing_store(receiver->elements(), receiver->GetIsolate()); return Subclass::AddArguments(receiver, backing_store, args, push_size, AT_END); } - static uint32_t UnshiftImpl(Handle receiver, BuiltinArguments* args, - uint32_t unshift_size) { + static Maybe UnshiftImpl(Handle receiver, + BuiltinArguments* args, + uint32_t unshift_size) { Handle backing_store(receiver->elements(), receiver->GetIsolate()); return Subclass::AddArguments(receiver, backing_store, args, unshift_size, @@ -2135,8 +2183,9 @@ class FastElementsAccessor : public ElementsAccessorBase { } } - static Object FillImpl(Handle receiver, Handle obj_value, - size_t start, size_t end) { + static MaybeHandle FillImpl(Handle receiver, + Handle obj_value, size_t start, + size_t end) { // Ensure indexes are within array bounds DCHECK_LE(0, start); DCHECK_LE(start, end); @@ -2149,8 +2198,8 @@ class FastElementsAccessor : public ElementsAccessorBase { // Make sure we have enough space. DCHECK_LE(end, std::numeric_limits::max()); if (end > Subclass::GetCapacityImpl(*receiver, receiver->elements())) { - Subclass::GrowCapacityAndConvertImpl(receiver, - static_cast(end)); + MAYBE_RETURN_NULL(Subclass::GrowCapacityAndConvertImpl( + receiver, static_cast(end))); CHECK_EQ(Subclass::kind(), receiver->GetElementsKind()); } DCHECK_LE(end, Subclass::GetCapacityImpl(*receiver, receiver->elements())); @@ -2158,7 +2207,7 @@ class FastElementsAccessor : public ElementsAccessorBase { for (size_t index = start; index < end; ++index) { Subclass::SetImpl(receiver, InternalIndex(index), *obj_value); } - return *receiver; + return MaybeHandle(receiver); } static Maybe IncludesValueImpl(Isolate* isolate, @@ -2320,8 +2369,8 @@ class FastElementsAccessor : public ElementsAccessorBase { return result; } - static Handle RemoveElement(Handle receiver, - Where remove_position) { + static MaybeHandle RemoveElement(Handle receiver, + Where remove_position) { Isolate* isolate = receiver->GetIsolate(); ElementsKind kind = KindTraits::Kind; if (IsSmiOrObjectElementsKind(kind)) { @@ -2339,24 +2388,26 @@ class FastElementsAccessor : public ElementsAccessorBase { Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length, 0, 0); } - Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store); + MAYBE_RETURN_NULL( + Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store)); if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) { return isolate->factory()->undefined_value(); } - return result; + return MaybeHandle(result); } - static uint32_t AddArguments(Handle receiver, - Handle backing_store, - BuiltinArguments* args, uint32_t add_size, - Where add_position) { + static Maybe AddArguments(Handle receiver, + Handle backing_store, + BuiltinArguments* args, uint32_t add_size, + Where add_position) { uint32_t length = Smi::ToInt(receiver->length()); DCHECK_LT(0, add_size); uint32_t elms_len = backing_store->length(); // Check we do not overflow the new_length. DCHECK(add_size <= static_cast(Smi::kMaxValue - length)); uint32_t new_length = length + add_size; + Isolate* isolate = receiver->GetIsolate(); if (new_length > elms_len) { // New backing storage is needed. @@ -2364,14 +2415,16 @@ class FastElementsAccessor : public ElementsAccessorBase { // If we add arguments to the start we have to shift the existing objects. int copy_dst_index = add_position == AT_START ? add_size : 0; // Copy over all objects to a new backing_store. - backing_store = Subclass::ConvertElementsWithCapacity( - receiver, backing_store, KindTraits::Kind, capacity, 0, - copy_dst_index); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, backing_store, + Subclass::ConvertElementsWithCapacity(receiver, backing_store, + KindTraits::Kind, capacity, 0, + copy_dst_index), + Nothing()); receiver->set_elements(*backing_store); } else if (add_position == AT_START) { // If the backing store has enough capacity and we add elements to the // start we have to shift the existing objects. - Isolate* isolate = receiver->GetIsolate(); Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0, length, 0, 0); } @@ -2381,7 +2434,7 @@ class FastElementsAccessor : public ElementsAccessorBase { Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index); // Set the length. receiver->set_length(Smi::FromInt(new_length)); - return new_length; + return Just(new_length); } static void CopyArguments(BuiltinArguments* args, @@ -2567,28 +2620,29 @@ class FastNonextensibleObjectElementsAccessor public: using BackingStore = typename KindTraits::BackingStore; - static uint32_t PushImpl(Handle receiver, BuiltinArguments* args, - uint32_t push_size) { + static Maybe PushImpl(Handle receiver, + BuiltinArguments* args, uint32_t push_size) { UNREACHABLE(); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { UNREACHABLE(); } // TODO(duongn): refactor this due to code duplication of sealed version. // Consider using JSObject::NormalizeElements(). Also consider follow the fast // element logic instead of changing to dictionary mode. - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { uint32_t old_length = 0; CHECK(array->length().ToArrayIndex(&old_length)); if (length == old_length) { // Do nothing. - return; + return Just(true); } // Transition to DICTIONARY_ELEMENTS. @@ -2620,8 +2674,8 @@ class FastNonextensibleObjectElementsAccessor // Set length. Handle new_backing_store(array->elements(), isolate); - DictionaryElementsAccessor::SetLengthImpl(isolate, array, length, - new_backing_store); + return DictionaryElementsAccessor::SetLengthImpl(isolate, array, length, + new_backing_store); } }; @@ -2660,30 +2714,33 @@ class FastSealedObjectElementsAccessor UNREACHABLE(); } - static Handle PopImpl(Handle receiver) { UNREACHABLE(); } - - static uint32_t PushImpl(Handle receiver, BuiltinArguments* args, - uint32_t push_size) { + static MaybeHandle PopImpl(Handle receiver) { UNREACHABLE(); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe PushImpl(Handle receiver, + BuiltinArguments* args, uint32_t push_size) { + UNREACHABLE(); + } + + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { UNREACHABLE(); } // TODO(duongn): refactor this due to code duplication of nonextensible // version. Consider using JSObject::NormalizeElements(). Also consider follow // the fast element logic instead of changing to dictionary mode. - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { uint32_t old_length = 0; CHECK(array->length().ToArrayIndex(&old_length)); if (length == old_length) { // Do nothing. - return; + return Just(true); } // Transition to DICTIONARY_ELEMENTS. @@ -2715,8 +2772,8 @@ class FastSealedObjectElementsAccessor // Set length Handle new_backing_store(array->elements(), isolate); - DictionaryElementsAccessor::SetLengthImpl(isolate, array, length, - new_backing_store); + return DictionaryElementsAccessor::SetLengthImpl(isolate, array, length, + new_backing_store); } }; @@ -2770,22 +2827,25 @@ class FastFrozenObjectElementsAccessor UNREACHABLE(); } - static Handle PopImpl(Handle receiver) { UNREACHABLE(); } - - static uint32_t PushImpl(Handle receiver, BuiltinArguments* args, - uint32_t push_size) { + static MaybeHandle PopImpl(Handle receiver) { UNREACHABLE(); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe PushImpl(Handle receiver, + BuiltinArguments* args, uint32_t push_size) { UNREACHABLE(); } - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { + UNREACHABLE(); + } + + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { UNREACHABLE(); } @@ -3123,9 +3183,9 @@ class TypedElementsAccessor return false; } - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle backing_store) { + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle backing_store) { // External arrays do not support changing their length. UNREACHABLE(); } @@ -3192,8 +3252,9 @@ class TypedElementsAccessor return Just(true); } - static Object FillImpl(Handle receiver, Handle value, - size_t start, size_t end) { + static MaybeHandle FillImpl(Handle receiver, + Handle value, size_t start, + size_t end) { Handle typed_array = Handle::cast(receiver); DCHECK(!typed_array->WasDetached()); DCHECK_LE(start, end); @@ -3208,7 +3269,7 @@ class TypedElementsAccessor } else { std::fill(data + start, data + end, scalar); } - return *typed_array; + return MaybeHandle(typed_array); } static Maybe IncludesValueImpl(Isolate* isolate, @@ -3945,13 +4006,13 @@ class SloppyArgumentsElementsAccessor } } - static void TransitionElementsKindImpl(Handle object, - Handle map) { + static Maybe TransitionElementsKindImpl(Handle object, + Handle map) { UNREACHABLE(); } - static void GrowCapacityAndConvertImpl(Handle object, - uint32_t capacity) { + static Maybe GrowCapacityAndConvertImpl(Handle object, + uint32_t capacity) { UNREACHABLE(); } @@ -3990,9 +4051,9 @@ class SloppyArgumentsElementsAccessor } } - static void SetLengthImpl(Isolate* isolate, Handle array, - uint32_t length, - Handle parameter_map) { + static Maybe SetLengthImpl(Isolate* isolate, Handle array, + uint32_t length, + Handle parameter_map) { // Sloppy arguments objects are not arrays. UNREACHABLE(); } @@ -4288,9 +4349,10 @@ class SlowSloppyArgumentsElementsAccessor NumberDictionary::DeleteEntry(isolate, dict, entry.adjust_down(length)); elements->set_arguments(*dict); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { Isolate* isolate = object->GetIsolate(); Handle elements( SloppyArgumentsElements::cast(object->elements()), isolate); @@ -4307,6 +4369,7 @@ class SlowSloppyArgumentsElementsAccessor if (*dictionary != *new_dictionary) { elements->set_arguments(*new_dictionary); } + return Just(true); } static void ReconfigureImpl(Handle object, @@ -4402,9 +4465,10 @@ class FastSloppyArgumentsElementsAccessor SlowSloppyArgumentsElementsAccessor::SloppyDeleteImpl(obj, elements, entry); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { DCHECK_EQ(NONE, attributes); Isolate* isolate = object->GetIsolate(); Handle elements( @@ -4412,7 +4476,8 @@ class FastSloppyArgumentsElementsAccessor Handle old_arguments(elements->arguments(), isolate); if (old_arguments->IsNumberDictionary() || static_cast(old_arguments->length()) < new_capacity) { - GrowCapacityAndConvertImpl(object, new_capacity); + MAYBE_RETURN(GrowCapacityAndConvertImpl(object, new_capacity), + Nothing()); } FixedArray arguments = elements->arguments(); // For fast holey objects, the entry equals the index. The code above made @@ -4422,6 +4487,7 @@ class FastSloppyArgumentsElementsAccessor // kMaxUInt32. FastHoleyObjectElementsAccessor::SetImpl(arguments, InternalIndex(index), *value); + return Just(true); } static void ReconfigureImpl(Handle object, @@ -4451,8 +4517,8 @@ class FastSloppyArgumentsElementsAccessor } } - static void GrowCapacityAndConvertImpl(Handle object, - uint32_t capacity) { + static Maybe GrowCapacityAndConvertImpl(Handle object, + uint32_t capacity) { Isolate* isolate = object->GetIsolate(); Handle elements( SloppyArgumentsElements::cast(object->elements()), isolate); @@ -4463,13 +4529,17 @@ class FastSloppyArgumentsElementsAccessor // elements. DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS || static_cast(old_arguments->length()) < capacity); - Handle arguments = - ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity); + Handle arguments; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, arguments, + ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity), + Nothing()); Handle new_map = JSObject::GetElementsTransitionMap( object, FAST_SLOPPY_ARGUMENTS_ELEMENTS); JSObject::MigrateToMap(isolate, object, new_map); elements->set_arguments(FixedArray::cast(*arguments)); JSObject::ValidateElements(*object); + return Just(true); } }; @@ -4541,9 +4611,10 @@ class StringWrapperElementsAccessor value); } - static void AddImpl(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) { + static Maybe AddImpl(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes, + uint32_t new_capacity) { DCHECK(index >= static_cast(GetString(*object).length())); // Explicitly grow fast backing stores if needed. Dictionaries know how to // extend their capacity themselves. @@ -4551,10 +4622,12 @@ class StringWrapperElementsAccessor (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS || BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) != new_capacity)) { - GrowCapacityAndConvertImpl(object, new_capacity); + MAYBE_RETURN(GrowCapacityAndConvertImpl(object, new_capacity), + Nothing()); } BackingStoreAccessor::AddImpl(object, index, value, attributes, new_capacity); + return Just(true); } static void ReconfigureImpl(Handle object, @@ -4599,8 +4672,8 @@ class StringWrapperElementsAccessor backing_store, keys); } - static void GrowCapacityAndConvertImpl(Handle object, - uint32_t capacity) { + static Maybe GrowCapacityAndConvertImpl(Handle object, + uint32_t capacity) { Handle old_elements(object->elements(), object->GetIsolate()); ElementsKind from_kind = object->GetElementsKind(); @@ -4615,9 +4688,9 @@ class StringWrapperElementsAccessor // elements. DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS || static_cast(old_elements->length()) < capacity); - Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind, - FAST_STRING_WRAPPER_ELEMENTS, - capacity); + return Subclass::BasicGrowCapacityAndConvertImpl( + object, old_elements, from_kind, FAST_STRING_WRAPPER_ELEMENTS, + capacity); } static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from, @@ -4702,7 +4775,7 @@ MaybeHandle ArrayConstructInitializeElements( } else { // Take the argument as the length. JSArray::Initialize(array, 0); - JSArray::SetLength(array, length); + MAYBE_RETURN_NULL(JSArray::SetLength(array, length)); } return array; } diff --git a/src/objects/elements.h b/src/objects/elements.h index 4a34e866f2..3f133208fa 100644 --- a/src/objects/elements.h +++ b/src/objects/elements.h @@ -66,7 +66,8 @@ class ElementsAccessor { // changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e. array that // have non-deletable elements can only be shrunk to the size of highest // element that is non-deletable. - virtual void SetLength(Handle holder, uint32_t new_length) = 0; + virtual Maybe SetLength(Handle holder, + uint32_t new_length) = 0; // Copy all indices that have elements from |object| into the given // KeyAccumulator. For Dictionary-based element-kinds we filter out elements @@ -96,13 +97,13 @@ class ElementsAccessor { Handle receiver, KeyAccumulator* accumulator, AddKeyConversion convert) = 0; - virtual void TransitionElementsKind(Handle object, - Handle map) = 0; - virtual void GrowCapacityAndConvert(Handle object, - uint32_t capacity) = 0; + virtual Maybe TransitionElementsKind(Handle object, + Handle map) = 0; + virtual Maybe GrowCapacityAndConvert(Handle object, + uint32_t capacity) = 0; // Unlike GrowCapacityAndConvert do not attempt to convert the backing store // and simply return false in this case. - virtual bool GrowCapacity(Handle object, uint32_t index) = 0; + virtual Maybe GrowCapacity(Handle object, uint32_t index) = 0; static void InitializeOncePerProcess(); static void TearDown(); @@ -110,29 +111,31 @@ class ElementsAccessor { virtual void Set(Handle holder, InternalIndex entry, Object value) = 0; - virtual void Add(Handle object, uint32_t index, - Handle value, PropertyAttributes attributes, - uint32_t new_capacity) = 0; + virtual Maybe Add(Handle object, uint32_t index, + Handle value, PropertyAttributes attributes, + uint32_t new_capacity) = 0; static Handle Concat(Isolate* isolate, BuiltinArguments* args, uint32_t concat_size, uint32_t result_length); - virtual uint32_t Push(Handle receiver, BuiltinArguments* args, - uint32_t push_size) = 0; + virtual Maybe Push(Handle receiver, BuiltinArguments* args, + uint32_t push_size) = 0; - virtual uint32_t Unshift(Handle receiver, BuiltinArguments* args, - uint32_t unshift_size) = 0; + virtual Maybe Unshift(Handle receiver, + BuiltinArguments* args, + uint32_t unshift_size) = 0; - virtual Handle Pop(Handle receiver) = 0; + virtual MaybeHandle Pop(Handle receiver) = 0; - virtual Handle Shift(Handle receiver) = 0; + virtual MaybeHandle Shift(Handle receiver) = 0; virtual Handle Normalize(Handle object) = 0; virtual size_t GetCapacity(JSObject holder, FixedArrayBase backing_store) = 0; - virtual Object Fill(Handle receiver, Handle obj_value, - size_t start, size_t end) = 0; + virtual MaybeHandle Fill(Handle receiver, + Handle obj_value, size_t start, + size_t end) = 0; // Check an Object's own elements for an element (using SameValueZero // semantics) diff --git a/src/objects/intl-objects.cc b/src/objects/intl-objects.cc index 015abcac99..f766fd7525 100644 --- a/src/objects/intl-objects.cc +++ b/src/objects/intl-objects.cc @@ -479,7 +479,12 @@ Handle InnerAddElement(Isolate* isolate, Handle array, field_type_string, NONE); JSObject::AddProperty(isolate, element, factory->value_string(), value, NONE); - JSObject::AddDataElement(array, index, element, NONE); + // TODO(victorgomes): Temporarily forcing a fatal error here in case of + // overflow, until Intl::AddElement can handle exceptions. + if (JSObject::AddDataElement(array, index, element, NONE).IsNothing()) { + FATAL("Fatal JavaScript invalid array size when adding element"); + UNREACHABLE(); + } return element; } @@ -1569,9 +1574,9 @@ std::vector BestFitSupportedLocales( } // ecma262 #sec-createarrayfromlist -Handle CreateArrayFromList(Isolate* isolate, - std::vector elements, - PropertyAttributes attr) { +MaybeHandle CreateArrayFromList(Isolate* isolate, + std::vector elements, + PropertyAttributes attr) { Factory* factory = isolate->factory(); // Let array be ! ArrayCreate(0). Handle array = factory->NewJSArray(0); @@ -1584,10 +1589,11 @@ Handle CreateArrayFromList(Isolate* isolate, const std::string& part = elements[i]; Handle value = factory->NewStringFromUtf8(CStrVector(part.c_str())).ToHandleChecked(); - JSObject::AddDataElement(array, i, value, attr); + MAYBE_RETURN(JSObject::AddDataElement(array, i, value, attr), + MaybeHandle()); } // 5. Return array. - return array; + return MaybeHandle(array); } // ECMA 402 9.2.9 SupportedLocales(availableLocales, requestedLocales, options) diff --git a/src/objects/js-array.h b/src/objects/js-array.h index a8b336d2be..776cb4446b 100644 --- a/src/objects/js-array.h +++ b/src/objects/js-array.h @@ -58,8 +58,8 @@ class JSArray : public JSObject { // Initializes the array to a certain length. inline bool AllowsSetLength(); - V8_EXPORT_PRIVATE static void SetLength(Handle array, - uint32_t length); + V8_EXPORT_PRIVATE static Maybe SetLength(Handle array, + uint32_t length); // Set the content of the array to the content of storage. static inline void SetContent(Handle array, diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc index 05c5099f85..90d2cac308 100644 --- a/src/objects/js-objects.cc +++ b/src/objects/js-objects.cc @@ -4849,9 +4849,9 @@ static ElementsKind BestFittingFastElementsKind(JSObject object) { } // static -void JSObject::AddDataElement(Handle object, uint32_t index, - Handle value, - PropertyAttributes attributes) { +Maybe JSObject::AddDataElement(Handle object, uint32_t index, + Handle value, + PropertyAttributes attributes) { Isolate* isolate = object->GetIsolate(); DCHECK(object->map(isolate).is_extensible()); @@ -4894,13 +4894,15 @@ void JSObject::AddDataElement(Handle object, uint32_t index, } to = GetMoreGeneralElementsKind(kind, to); ElementsAccessor* accessor = ElementsAccessor::ForKind(to); - accessor->Add(object, index, value, attributes, new_capacity); + MAYBE_RETURN(accessor->Add(object, index, value, attributes, new_capacity), + Nothing()); if (object->IsJSArray(isolate) && index >= old_length) { Handle new_length = isolate->factory()->NewNumberFromUint(index + 1); JSArray::cast(*object).set_length(*new_length); } + return Just(true); } template @@ -4967,7 +4969,15 @@ void JSObject::TransitionElementsKind(Handle object, DCHECK((IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) || (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind))); uint32_t c = static_cast(object->elements().length()); - ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); + if (ElementsAccessor::ForKind(to_kind) + ->GrowCapacityAndConvert(object, c) + .IsNothing()) { + // TODO(victorgomes): Temporarily forcing a fatal error here in case of + // overflow, until all users of TransitionElementsKind can handle + // exceptions. + FATAL("Fatal JavaScript invalid array size transitioning elements kind."); + UNREACHABLE(); + } } } diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h index f75f658858..2e94bf17a9 100644 --- a/src/objects/js-objects.h +++ b/src/objects/js-objects.h @@ -440,10 +440,9 @@ class JSObject : public TorqueGeneratedJSObject { const char* name, Handle value, PropertyAttributes attributes); - V8_EXPORT_PRIVATE static void AddDataElement(Handle receiver, - uint32_t index, - Handle value, - PropertyAttributes attributes); + V8_EXPORT_PRIVATE static Maybe AddDataElement( + Handle receiver, uint32_t index, Handle value, + PropertyAttributes attributes); // Extend the receiver with a single fast property appeared first in the // passed map. This also extends the property backing store if necessary. diff --git a/src/objects/objects.cc b/src/objects/objects.cc index e061da6120..9011c460c5 100644 --- a/src/objects/objects.cc +++ b/src/objects/objects.cc @@ -2899,8 +2899,9 @@ Maybe Object::AddDataProperty(LookupIterator* it, Handle value, } Handle receiver_obj = Handle::cast(receiver); - JSObject::AddDataElement(receiver_obj, it->array_index(), value, - attributes); + MAYBE_RETURN(JSObject::AddDataElement(receiver_obj, it->array_index(), + value, attributes), + Nothing()); JSObject::ValidateElements(*receiver_obj); return Just(true); } else { @@ -3418,7 +3419,7 @@ Maybe JSArray::ArraySetLength(Isolate* isolate, Handle a, // (Not needed.) } // Most of steps 16 through 19 is implemented by JSArray::SetLength. - JSArray::SetLength(a, new_len); + MAYBE_RETURN(JSArray::SetLength(a, new_len), Nothing()); // Steps 19d-ii, 20. if (!new_writable) { PropertyDescriptor readonly; @@ -5102,13 +5103,13 @@ void JSArray::Initialize(Handle array, int capacity, int length) { array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); } -void JSArray::SetLength(Handle array, uint32_t new_length) { +Maybe JSArray::SetLength(Handle array, uint32_t new_length) { // We should never end in here with a pixel or external array. DCHECK(array->AllowsSetLength()); if (array->SetLengthWouldNormalize(new_length)) { JSObject::NormalizeElements(array); } - array->GetElementsAccessor()->SetLength(array, new_length); + return array->GetElementsAccessor()->SetLength(array, new_length); } // ES6: 9.5.2 [[SetPrototypeOf]] (V) diff --git a/src/objects/value-serializer.cc b/src/objects/value-serializer.cc index bc0b82ec4a..9984f097a4 100644 --- a/src/objects/value-serializer.cc +++ b/src/objects/value-serializer.cc @@ -1548,7 +1548,7 @@ MaybeHandle ValueDeserializer::ReadSparseJSArray() { HandleScope scope(isolate_); Handle array = isolate_->factory()->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND); - JSArray::SetLength(array, length); + MAYBE_RETURN(JSArray::SetLength(array, length), MaybeHandle()); AddObjectWithID(id, array); uint32_t num_properties; @@ -2321,7 +2321,7 @@ ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() { Handle js_array = isolate_->factory()->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND); - JSArray::SetLength(js_array, length); + MAYBE_RETURN_NULL(JSArray::SetLength(js_array, length)); size_t begin_properties = stack.size() - 2 * static_cast(num_properties); if (num_properties && diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc index 623064fd8a..bdfb666ab7 100644 --- a/src/runtime/runtime-array.cc +++ b/src/runtime/runtime-array.cc @@ -28,7 +28,14 @@ RUNTIME_FUNCTION(Runtime_TransitionElementsKind) { CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); CONVERT_ARG_HANDLE_CHECKED(Map, to_map, 1); ElementsKind to_kind = to_map->elements_kind(); - ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map); + if (ElementsAccessor::ForKind(to_kind) + ->TransitionElementsKind(object, to_map) + .IsNothing()) { + // TODO(victorgomes): EffectControlLinearizer::LowerTransitionElementsKind + // does not handle exceptions. + FATAL("Fatal JavaScript invalid array size"); + UNREACHABLE(); + } return *object; } @@ -180,7 +187,11 @@ RUNTIME_FUNCTION(Runtime_GrowArrayElements) { uint32_t capacity = static_cast(object->elements().length()); if (index >= capacity) { - if (!object->GetElementsAccessor()->GrowCapacity(object, index)) { + bool has_grown; + MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, has_grown, + object->GetElementsAccessor()->GrowCapacity(object, index)); + if (!has_grown) { return Smi::zero(); } }