Commit e10fdbed authored by cbruni's avatar cbruni Committed by Commit bot

[proxies] Limit recursive proxy prototype lookups to 100'000

Creating proto-recursive proxies might lead to instanceof while-looping
endlessly in Object::HasInPrototypeChain (For traps we already have stack
guards in place to prevent stack overflows). We prevent this by limiting
the number of proxies we visit in PrototypeIterator to a magic large number.

LOG=n
BUG=v8:1534

Review URL: https://codereview.chromium.org/1542583003

Cr-Commit-Position: refs/heads/master@{#33007}
parent a878dcfd
......@@ -28,12 +28,15 @@ class PrototypeIterator {
enum WhereToEnd { END_AT_NULL, END_AT_NON_HIDDEN };
const int kProxyPrototypeLimit = 100 * 1000;
PrototypeIterator(Isolate* isolate, Handle<Object> receiver,
WhereToStart where_to_start = START_AT_PROTOTYPE)
: did_jump_to_prototype_chain_(false),
object_(NULL),
handle_(receiver),
isolate_(isolate) {
isolate_(isolate),
seen_proxies_(0) {
CHECK(!handle_.is_null());
if (where_to_start == START_AT_PROTOTYPE) {
Advance();
......@@ -44,7 +47,8 @@ class PrototypeIterator {
WhereToStart where_to_start = START_AT_PROTOTYPE)
: did_jump_to_prototype_chain_(false),
object_(receiver),
isolate_(isolate) {
isolate_(isolate),
seen_proxies_(0) {
if (where_to_start == START_AT_PROTOTYPE) {
Advance();
}
......@@ -127,14 +131,22 @@ class PrototypeIterator {
handle_ = isolate_->factory()->null_value();
return true;
}
if (!handle_.is_null() && handle_->IsJSProxy()) {
did_jump_to_prototype_chain_ = true;
MaybeHandle<Object> proto =
JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
return proto.ToHandle(&handle_);
if (handle_.is_null() || !handle_->IsJSProxy()) {
AdvanceIgnoringProxies();
return true;
}
AdvanceIgnoringProxies();
return true;
// Due to possible __proto__ recursion limit the number of Proxies
// we visit to an arbitrarily chosen large number.
seen_proxies_++;
if (seen_proxies_ > kProxyPrototypeLimit) {
isolate_->Throw(
*isolate_->factory()->NewRangeError(MessageTemplate::kStackOverflow));
return false;
}
did_jump_to_prototype_chain_ = true;
MaybeHandle<Object> proto =
JSProxy::GetPrototype(Handle<JSProxy>::cast(handle_));
return proto.ToHandle(&handle_);
}
bool IsAtEnd(WhereToEnd where_to_end = END_AT_NULL) const {
......@@ -166,6 +178,7 @@ class PrototypeIterator {
Object* object_;
Handle<Object> handle_;
Isolate* isolate_;
int seen_proxies_;
DISALLOW_COPY_AND_ASSIGN(PrototypeIterator);
};
......
......@@ -7,7 +7,7 @@
// Test instanceof with proxies.
function TestInstanceOfWithProxies() {
(function TestInstanceOfWithProxies() {
function foo(x) {
return x instanceof Array;
}
......@@ -47,6 +47,16 @@ function TestInstanceOfWithProxies() {
assertTrue(foo_catch(o));
handler.getPrototypeOf = function(target) { return Array.prototype; }
assertFalse(foo_catch(o));
}
})();
TestInstanceOfWithProxies();
(function testInstanceOfWithRecursiveProxy() {
// Make sure we gracefully deal with recursive proxies.
var proxy = new Proxy({},{});
proxy.__proto__ = proxy;
// instanceof will cause an inifinite prototype walk.
assertThrows(() => { proxy instanceof Object }, RangeError);
var proxy2 = new Proxy({}, {getPrototypeOf() { return proxy2 }});
assertThrows(() => { proxy instanceof Object }, 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