[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}
This commit is contained in:
parent
a878dcfdbc
commit
e10fdbed6d
@ -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);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user