[strong] Add tests for loading from proxy, super, with access checks

Followup for https://codereview.chromium.org/1168093002/

These seem to already function correctly without the need for further runtime
changes.

There will be a final follow-up for interceptors.

BUG=v8:3956
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#29389}
This commit is contained in:
conradw 2015-06-30 10:13:08 -07:00 committed by Commit bot
parent abaa094a2b
commit ea4e568363
4 changed files with 357 additions and 1 deletions

View File

@ -21424,6 +21424,164 @@ TEST(SealHandleScopeNested) {
}
static bool access_was_called = false;
static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global,
Local<Value> name, v8::AccessType type,
Local<Value> data) {
access_was_called = true;
return true;
}
static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global,
Local<Value> name, v8::AccessType type,
Local<Value> data) {
access_was_called = true;
return false;
}
TEST(StrongModeAccessCheckAllowed) {
i::FLAG_strong_mode = true;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Handle<Value> value;
access_was_called = false;
v8::Handle<v8::ObjectTemplate> obj_template =
v8::ObjectTemplate::New(isolate);
obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL);
// Create an environment
v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
context0->Enter();
v8::Handle<v8::Object> global0 = context0->Global();
global0->Set(v8_str("object"), obj_template->NewInstance());
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.x");
CHECK(!try_catch.HasCaught());
CHECK(!access_was_called);
CHECK_EQ(42, value->Int32Value());
}
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.foo");
CHECK(try_catch.HasCaught());
CHECK(!access_was_called);
}
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object[10]");
CHECK(try_catch.HasCaught());
CHECK(!access_was_called);
}
// Create an environment
v8::Local<Context> context1 = Context::New(isolate);
context1->Enter();
v8::Handle<v8::Object> global1 = context1->Global();
global1->Set(v8_str("object"), obj_template->NewInstance());
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.x");
CHECK(!try_catch.HasCaught());
CHECK(access_was_called);
CHECK_EQ(42, value->Int32Value());
}
access_was_called = false;
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.foo");
CHECK(try_catch.HasCaught());
CHECK(access_was_called);
}
access_was_called = false;
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object[10]");
CHECK(try_catch.HasCaught());
CHECK(access_was_called);
}
context1->Exit();
context0->Exit();
}
TEST(StrongModeAccessCheckBlocked) {
i::FLAG_strong_mode = true;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Handle<Value> value;
access_was_called = false;
v8::Handle<v8::ObjectTemplate> obj_template =
v8::ObjectTemplate::New(isolate);
obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL);
// Create an environment
v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
context0->Enter();
v8::Handle<v8::Object> global0 = context0->Global();
global0->Set(v8_str("object"), obj_template->NewInstance());
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.x");
CHECK(!try_catch.HasCaught());
CHECK(!access_was_called);
CHECK_EQ(42, value->Int32Value());
}
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.foo");
CHECK(try_catch.HasCaught());
CHECK(!access_was_called);
}
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object[10]");
CHECK(try_catch.HasCaught());
CHECK(!access_was_called);
}
// Create an environment
v8::Local<Context> context1 = Context::New(isolate);
context1->Enter();
v8::Handle<v8::Object> global1 = context1->Global();
global1->Set(v8_str("object"), obj_template->NewInstance());
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.x");
CHECK(try_catch.HasCaught());
CHECK(access_was_called);
}
access_was_called = false;
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object.foo");
CHECK(try_catch.HasCaught());
CHECK(access_was_called);
}
access_was_called = false;
{
v8::TryCatch try_catch(isolate);
value = CompileRun("'use strong'; object[10]");
CHECK(try_catch.HasCaught());
CHECK(access_was_called);
}
context1->Exit();
context0->Exit();
}
TEST(StrongModeArityCallFromApi) {
i::FLAG_strong_mode = true;
LocalContext env;

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --strong-mode --allow-natives-syntax
// Flags: --strong-mode
function getGlobal() {
return this;

View File

@ -0,0 +1,96 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-proxies --strong-mode
// Forwarding proxies adapted from proposal definition
function handlerMaker1(obj) {
return {
getPropertyDescriptor: function(name) {
var desc;
var searchObj = obj;
while (desc === undefined && searchObj != null) {
desc = Object.getOwnPropertyDescriptor(searchObj, name);
searchObj = searchObj.__proto__;
}
// a trapping proxy's properties must always be configurable
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
fix: function() {
if (Object.isFrozen(obj)) {
var result = {};
Object.getOwnPropertyNames(obj).forEach(function(name) {
result[name] = Object.getOwnPropertyDescriptor(obj, name);
});
return result;
}
// As long as obj is not frozen, the proxy won't allow itself to be fixed
return undefined; // will cause a TypeError to be thrown
}
};
}
function handlerMaker2(obj) {
return {
get: function(receiver, name) {
return obj[name];
},
fix: function() {
if (Object.isFrozen(obj)) {
var result = {};
Object.getOwnPropertyNames(obj).forEach(function(name) {
result[name] = Object.getOwnPropertyDescriptor(obj, name);
});
return result;
}
// As long as obj is not frozen, the proxy won't allow itself to be fixed
return undefined; // will cause a TypeError to be thrown
}
};
}
var baseObj = {};
var proxy1 = Proxy.create(handlerMaker1(baseObj));
var proxy2 = Proxy.create(handlerMaker2(baseObj));
var childObj1 = { __proto__: proxy1 };
var childObj2 = { __proto__: proxy2 };
var childObjAccessor1 = { set foo(_){}, set "1"(_){}, __proto__: proxy1 };
var childObjAccessor2 = { set foo(_){}, set "1"(_){}, __proto__: proxy2 };
(function() {
"use strong";
// TODO(conradw): These asserts are sanity checking V8's proxy implementation.
// Strong mode semantics for ES6 proxies still need to be explored.
assertDoesNotThrow(function(){proxy1.foo});
assertDoesNotThrow(function(){proxy1[1]});
assertDoesNotThrow(function(){proxy2.foo});
assertDoesNotThrow(function(){proxy2[1]});
assertDoesNotThrow(function(){childObj1.foo});
assertDoesNotThrow(function(){childObj1[1]});
assertDoesNotThrow(function(){childObj2.foo});
assertDoesNotThrow(function(){childObj2[1]});
assertThrows(function(){baseObj.foo}, TypeError);
assertThrows(function(){baseObj[1]}, TypeError);
assertThrows(function(){childObjAccessor1.foo}, TypeError);
assertThrows(function(){childObjAccessor1[1]}, TypeError);
assertThrows(function(){childObjAccessor2.foo}, TypeError);
assertThrows(function(){childObjAccessor2[1]}, TypeError);
// Once the proxy is no longer trapping, property access should have strong
// semantics.
Object.freeze(baseObj);
Object.freeze(proxy1);
Object.freeze(proxy2);
assertThrows(function(){proxy1.foo}, TypeError);
assertThrows(function(){proxy1[1]}, TypeError);
assertThrows(function(){proxy2.foo}, TypeError);
assertThrows(function(){proxy2[1]}, TypeError);
assertThrows(function(){childObj1.foo}, TypeError);
assertThrows(function(){childObj1[1]}, TypeError);
assertThrows(function(){childObj2.foo}, TypeError);
assertThrows(function(){childObj2[1]}, TypeError);
assertThrows(function(){childObjAccessor1.foo}, TypeError);
assertThrows(function(){childObjAccessor1[1]}, TypeError);
assertThrows(function(){childObjAccessor2.foo}, TypeError);
assertThrows(function(){childObjAccessor2[1]}, TypeError);
})();

View File

@ -0,0 +1,102 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --strong-mode
"use strong";
function testSuper(object) {
assertEquals(0, object.validLoad());
assertThrows(function(){ return object.propertyLoad() }, TypeError);
assertThrows(function(){ return object.elementLoad() }, TypeError);
assertThrows(function(){ return object.accessorLoad() }, TypeError);
}
class A {
constructor() {}
foo() {
return 0;
}
get bar() {
return 0;
}
set baz(_) {
return;
}
}
class B extends A {
constructor() {
super();
}
validLoad() {
return super.foo() + super.bar;
}
propertyLoad() {
return super.x;
}
elementLoad() {
return super[1];
}
accessorLoad() {
return super.baz;
}
}
class C extends A {
constructor() {
super();
this[1] = 0;
this.x = 0;
}
get baz() {
return 0;
}
validLoad() {
return super.foo() + super.bar;
}
propertyLoad() {
return super.x;
}
elementLoad() {
return super[1];
}
accessorLoad() {
return super.baz;
}
}
let b = new B();
let c = new C();
testSuper(b);
testSuper(c);
let d = {
"0": 0,
foo: 0,
bar: (function(){return 0}),
get baz(){return 0},
set qux(_){return}
}
let e = {
__proto__: d,
"1": 0,
x: 0,
get baz(){return 0},
validLoad() {
return super[0] + super.foo + super.bar() + super.baz;
},
propertyLoad() {
return super.x;
},
elementLoad() {
return super[1];
},
accessorLoad() {
return super.qux;
}
}
testSuper(e);