Commit cdd58d08 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[proxies] Add stackoverflow check for JSProxy::isArray

Bug: chromium:727000
Change-Id: I0fb6fecc9564aee97bcf7c0e9201c580572061be
Reviewed-on: https://chromium-review.googlesource.com/525717
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45767}
parent a41db446
...@@ -469,6 +469,15 @@ bool Object::IsPrimitive() const { ...@@ -469,6 +469,15 @@ bool Object::IsPrimitive() const {
return IsSmi() || HeapObject::cast(this)->map()->IsPrimitiveMap(); return IsSmi() || HeapObject::cast(this)->map()->IsPrimitiveMap();
} }
// static
Maybe<bool> Object::IsArray(Handle<Object> object) {
if (object->IsSmi()) return Just(false);
Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
if (heap_object->IsJSArray()) return Just(true);
if (!heap_object->IsJSProxy()) return Just(false);
return JSProxy::IsArray(Handle<JSProxy>::cast(object));
}
bool HeapObject::IsJSGlobalProxy() const { bool HeapObject::IsJSGlobalProxy() const {
bool result = map()->instance_type() == JS_GLOBAL_PROXY_TYPE; bool result = map()->instance_type() == JS_GLOBAL_PROXY_TYPE;
DCHECK(!result || map()->is_access_check_needed()); DCHECK(!result || map()->is_access_check_needed());
......
...@@ -853,23 +853,6 @@ MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object, ...@@ -853,23 +853,6 @@ MaybeHandle<Object> Object::InstanceOf(Isolate* isolate, Handle<Object> object,
return result; return result;
} }
Maybe<bool> Object::IsArray(Handle<Object> object) {
if (object->IsJSArray()) return Just(true);
if (object->IsJSProxy()) {
Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
Isolate* isolate = proxy->GetIsolate();
if (proxy->IsRevoked()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyRevoked,
isolate->factory()->NewStringFromAsciiChecked("IsArray")));
return Nothing<bool>();
}
return Object::IsArray(handle(proxy->target(), isolate));
}
return Just(false);
}
// static // static
MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver, MaybeHandle<Object> Object::GetMethod(Handle<JSReceiver> receiver,
Handle<Name> name) { Handle<Name> name) {
...@@ -5068,6 +5051,27 @@ void JSProxy::Revoke(Handle<JSProxy> proxy) { ...@@ -5068,6 +5051,27 @@ void JSProxy::Revoke(Handle<JSProxy> proxy) {
DCHECK(proxy->IsRevoked()); DCHECK(proxy->IsRevoked());
} }
// static
Maybe<bool> JSProxy::IsArray(Handle<JSProxy> proxy) {
Isolate* isolate = proxy->GetIsolate();
Handle<JSReceiver> object = Handle<JSReceiver>::cast(proxy);
for (int i = 0; i < JSProxy::kMaxIterationLimit; i++) {
Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
if (proxy->IsRevoked()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyRevoked,
isolate->factory()->NewStringFromAsciiChecked("IsArray")));
return Nothing<bool>();
}
object = handle(proxy->target(), isolate);
if (object->IsJSArray()) return Just(true);
if (!object->IsJSProxy()) return Just(false);
}
// Too deep recursion, throw a RangeError.
isolate->StackOverflow();
return Nothing<bool>();
}
Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Name> name) { Handle<Name> name) {
......
...@@ -1182,8 +1182,8 @@ class Object { ...@@ -1182,8 +1182,8 @@ class Object {
STRUCT_LIST(DECLARE_STRUCT_PREDICATE) STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
#undef DECLARE_STRUCT_PREDICATE #undef DECLARE_STRUCT_PREDICATE
// ES6, section 7.2.2 IsArray. NOT to be confused with %_IsArray. // ES6, #sec-isarray. NOT to be confused with %_IsArray.
MUST_USE_RESULT static Maybe<bool> IsArray(Handle<Object> object); INLINE(MUST_USE_RESULT static Maybe<bool> IsArray(Handle<Object> object));
INLINE(bool IsNameDictionary() const); INLINE(bool IsNameDictionary() const);
INLINE(bool IsGlobalDictionary() const); INLINE(bool IsGlobalDictionary() const);
...@@ -7320,6 +7320,9 @@ class JSProxy: public JSReceiver { ...@@ -7320,6 +7320,9 @@ class JSProxy: public JSReceiver {
// ES6 9.5.3 // ES6 9.5.3
MUST_USE_RESULT static Maybe<bool> IsExtensible(Handle<JSProxy> proxy); MUST_USE_RESULT static Maybe<bool> IsExtensible(Handle<JSProxy> proxy);
// ES6, #sec-isarray. NOT to be confused with %_IsArray.
MUST_USE_RESULT static Maybe<bool> IsArray(Handle<JSProxy> proxy);
// ES6 9.5.4 (when passed DONT_THROW) // ES6 9.5.4 (when passed DONT_THROW)
MUST_USE_RESULT static Maybe<bool> PreventExtensions( MUST_USE_RESULT static Maybe<bool> PreventExtensions(
Handle<JSProxy> proxy, ShouldThrow should_throw); Handle<JSProxy> proxy, ShouldThrow should_throw);
...@@ -7367,6 +7370,8 @@ class JSProxy: public JSReceiver { ...@@ -7367,6 +7370,8 @@ class JSProxy: public JSReceiver {
DECLARE_PRINTER(JSProxy) DECLARE_PRINTER(JSProxy)
DECLARE_VERIFIER(JSProxy) DECLARE_VERIFIER(JSProxy)
static const int kMaxIterationLimit = 100 * 1024;
// Layout description. // Layout description.
static const int kTargetOffset = JSReceiver::kHeaderSize; static const int kTargetOffset = JSReceiver::kHeaderSize;
static const int kHandlerOffset = kTargetOffset + kPointerSize; static const int kHandlerOffset = kTargetOffset + kPointerSize;
......
...@@ -27,8 +27,6 @@ class PrototypeIterator { ...@@ -27,8 +27,6 @@ class PrototypeIterator {
public: public:
enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN }; enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
const int kProxyPrototypeLimit = 100 * 1000;
PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver, PrototypeIterator(Isolate* isolate, Handle<JSReceiver> receiver,
WhereToStart where_to_start = kStartAtPrototype, WhereToStart where_to_start = kStartAtPrototype,
WhereToEnd where_to_end = END_AT_NULL) WhereToEnd where_to_end = END_AT_NULL)
...@@ -160,7 +158,7 @@ class PrototypeIterator { ...@@ -160,7 +158,7 @@ class PrototypeIterator {
// Due to possible __proto__ recursion limit the number of Proxies // Due to possible __proto__ recursion limit the number of Proxies
// we visit to an arbitrarily chosen large number. // we visit to an arbitrarily chosen large number.
seen_proxies_++; seen_proxies_++;
if (seen_proxies_ > kProxyPrototypeLimit) { if (seen_proxies_ > JSProxy::kMaxIterationLimit) {
isolate_->StackOverflow(); isolate_->StackOverflow();
return false; return false;
} }
......
...@@ -6,9 +6,21 @@ ...@@ -6,9 +6,21 @@
assertTrue(Array.isArray([])); assertTrue(Array.isArray([]));
assertFalse(Array.isArray({})); assertFalse(Array.isArray({}));
assertFalse(Array.isArray(null)); assertFalse(Array.isArray(null));
assertFalse(Array.isArray(0));
assertFalse(Array.isArray(0.1));
assertFalse(Array.isArray(""));
assertFalse(Array.isArray(undefined));
assertTrue(Array.isArray(new Proxy([], {}))); assertTrue(Array.isArray(new Proxy([], {})));
assertFalse(Array.isArray(new Proxy({}, {}))); assertFalse(Array.isArray(new Proxy({}, {})));
assertTrue(Array.isArray(new Proxy(new Proxy([], {}), {}))); assertTrue(Array.isArray(new Proxy(new Proxy([], {}), {})));
assertFalse(Array.isArray(new Proxy(new Proxy({}, {}), {}))); assertFalse(Array.isArray(new Proxy(new Proxy({}, {}), {})));
(function TestIsArrayStackOverflow() {
var proxy = new Proxy([], {});
for(var i=0; i<200*1024; i++) {
proxy = new Proxy(proxy, {});
}
assertThrows(()=>Array.isArray(proxy), RangeError);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment