Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index cfd18780795be70e6aa75736cf43e16ba11eb6e5..20fd66b37eb90b1f1523627350edace29096bfa9 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -433,12 +433,19 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter( |
static bool FindAllCanReadHolder(LookupIterator* it) { |
- for (; it->IsFound(); it->Next()) { |
+ // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of |
+ // which have already been checked. |
+ DCHECK(it->state() == LookupIterator::ACCESS_CHECK || |
+ it->state() == LookupIterator::INTERCEPTOR); |
+ for (it->Next(); it->IsFound(); it->Next()) { |
if (it->state() == LookupIterator::ACCESSOR) { |
- Handle<Object> accessors = it->GetAccessors(); |
+ auto accessors = it->GetAccessors(); |
if (accessors->IsAccessorInfo()) { |
if (AccessorInfo::cast(*accessors)->all_can_read()) return true; |
} |
+ } else if (it->state() == LookupIterator::INTERCEPTOR) { |
+ auto holder = it->GetHolder<JSObject>(); |
+ if (holder->GetNamedInterceptor()->all_can_read()) return true; |
} |
} |
return false; |
@@ -448,10 +455,18 @@ static bool FindAllCanReadHolder(LookupIterator* it) { |
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( |
LookupIterator* it) { |
Handle<JSObject> checked = it->GetHolder<JSObject>(); |
- if (FindAllCanReadHolder(it)) { |
- return GetPropertyWithAccessor(it->GetReceiver(), it->name(), |
- it->GetHolder<JSObject>(), |
- it->GetAccessors()); |
+ while (FindAllCanReadHolder(it)) { |
+ if (it->state() == LookupIterator::ACCESSOR) { |
+ return GetPropertyWithAccessor(it->GetReceiver(), it->name(), |
+ it->GetHolder<JSObject>(), |
+ it->GetAccessors()); |
+ } |
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
+ auto receiver = Handle<JSObject>::cast(it->GetReceiver()); |
+ auto result = GetPropertyWithInterceptor(it->GetHolder<JSObject>(), |
+ receiver, it->name()); |
+ if (it->isolate()->has_scheduled_exception()) break; |
+ if (!result.is_null()) return result; |
} |
it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET); |
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
@@ -462,8 +477,16 @@ MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck( |
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( |
LookupIterator* it) { |
Handle<JSObject> checked = it->GetHolder<JSObject>(); |
- if (FindAllCanReadHolder(it)) |
- return maybe(it->property_details().attributes()); |
+ while (FindAllCanReadHolder(it)) { |
+ if (it->state() == LookupIterator::ACCESSOR) { |
+ return maybe(it->property_details().attributes()); |
+ } |
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
+ auto result = GetPropertyAttributesWithInterceptor( |
+ it->GetHolder<JSObject>(), it->GetReceiver(), it->name()); |
+ if (it->isolate()->has_scheduled_exception()) break; |
+ if (result.has_value && result.value != ABSENT) return result; |
+ } |
it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS); |
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), |
Maybe<PropertyAttributes>()); |
@@ -550,6 +573,65 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object, |
} |
+static MaybeHandle<JSObject> FindIndexedAllCanReadHolder( |
+ Isolate* isolate, Handle<JSObject> js_object, |
+ PrototypeIterator::WhereToStart where_to_start) { |
+ for (PrototypeIterator iter(isolate, js_object, where_to_start); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ auto curr = PrototypeIterator::GetCurrent(iter); |
+ if (!curr->IsJSObject()) break; |
+ auto obj = Handle<JSObject>::cast(curr); |
+ if (!obj->HasIndexedInterceptor()) continue; |
+ if (obj->GetIndexedInterceptor()->all_can_read()) return obj; |
+ } |
+ return MaybeHandle<JSObject>(); |
+} |
+ |
+ |
+MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck( |
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
+ uint32_t index) { |
+ Handle<JSObject> holder = object; |
+ PrototypeIterator::WhereToStart where_to_start = |
+ PrototypeIterator::START_AT_RECEIVER; |
+ while (true) { |
+ auto all_can_read_holder = |
+ FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
+ if (!all_can_read_holder.ToHandle(&holder)) break; |
+ auto result = |
+ JSObject::GetElementWithInterceptor(holder, receiver, index, false); |
+ if (isolate->has_scheduled_exception()) break; |
+ if (!result.is_null()) return result; |
+ where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
+ } |
+ isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ return isolate->factory()->undefined_value(); |
+} |
+ |
+ |
+Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( |
+ Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
+ uint32_t index) { |
+ Handle<JSObject> holder = object; |
+ PrototypeIterator::WhereToStart where_to_start = |
+ PrototypeIterator::START_AT_RECEIVER; |
+ while (true) { |
+ auto all_can_read_holder = |
+ FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
+ if (!all_can_read_holder.ToHandle(&holder)) break; |
+ auto result = |
+ JSObject::GetElementAttributeFromInterceptor(object, receiver, index); |
+ if (isolate->has_scheduled_exception()) break; |
+ if (result.has_value && result.value != ABSENT) return result; |
+ where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
+ } |
+ isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS); |
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>()); |
+ return maybe(ABSENT); |
+} |
+ |
+ |
MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
Handle<Object> object, |
Handle<Object> receiver, |
@@ -582,14 +664,14 @@ MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, |
// Check access rights if needed. |
if (js_object->IsAccessCheckNeeded()) { |
if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) { |
- isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- return isolate->factory()->undefined_value(); |
+ return JSObject::GetElementWithFailedAccessCheck(isolate, js_object, |
+ receiver, index); |
} |
} |
if (js_object->HasIndexedInterceptor()) { |
- return JSObject::GetElementWithInterceptor(js_object, receiver, index); |
+ return JSObject::GetElementWithInterceptor(js_object, receiver, index, |
+ true); |
} |
if (js_object->elements() != isolate->heap()->empty_fixed_array()) { |
@@ -4012,9 +4094,8 @@ Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver( |
// Check access rights if needed. |
if (object->IsAccessCheckNeeded()) { |
if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) { |
- isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS); |
- RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>()); |
- return maybe(ABSENT); |
+ return GetElementAttributesWithFailedAccessCheck(isolate, object, |
+ receiver, index); |
} |
} |
@@ -13264,10 +13345,10 @@ MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
} |
-MaybeHandle<Object> JSObject::GetElementWithInterceptor( |
- Handle<JSObject> object, |
- Handle<Object> receiver, |
- uint32_t index) { |
+MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object, |
+ Handle<Object> receiver, |
+ uint32_t index, |
+ bool check_prototype) { |
Isolate* isolate = object->GetIsolate(); |
// Make sure that the top context does not change when doing |
@@ -13292,6 +13373,8 @@ MaybeHandle<Object> JSObject::GetElementWithInterceptor( |
} |
} |
+ if (!check_prototype) return MaybeHandle<Object>(); |
+ |
ElementsAccessor* handler = object->GetElementsAccessor(); |
Handle<Object> result; |
ASSIGN_RETURN_ON_EXCEPTION( |