Index: test/cctest/test-access-checks.cc |
diff --git a/test/cctest/test-access-checks.cc b/test/cctest/test-access-checks.cc |
index 34b64c400a8550ae64279ccd3f2657e5802db688..937e875d7ed7b8426e9da03407914430d10a6cf5 100644 |
--- a/test/cctest/test-access-checks.cc |
+++ b/test/cctest/test-access-checks.cc |
@@ -10,8 +10,11 @@ namespace { |
int32_t g_cross_context_int = 0; |
+bool g_expect_interceptor_call = false; |
+ |
void NamedGetter(v8::Local<v8::Name> property, |
const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (property->Equals(context, v8_str("cross_context_int")).FromJust()) |
@@ -20,6 +23,7 @@ void NamedGetter(v8::Local<v8::Name> property, |
void NamedSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value, |
const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) |
@@ -32,6 +36,7 @@ void NamedSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value, |
void NamedQuery(v8::Local<v8::Name> property, |
const v8::PropertyCallbackInfo<v8::Integer>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) |
@@ -41,6 +46,7 @@ void NamedQuery(v8::Local<v8::Name> property, |
void NamedDeleter(v8::Local<v8::Name> property, |
const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (!property->Equals(context, v8_str("cross_context_int")).FromJust()) |
@@ -49,6 +55,7 @@ void NamedDeleter(v8::Local<v8::Name> property, |
} |
void NamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
v8::Local<v8::Array> names = v8::Array::New(isolate, 1); |
@@ -58,11 +65,13 @@ void NamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { |
void IndexedGetter(uint32_t index, |
const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ CHECK(g_expect_interceptor_call); |
if (index == 7) info.GetReturnValue().Set(g_cross_context_int); |
} |
void IndexedSetter(uint32_t index, v8::Local<v8::Value> value, |
const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (index != 7) return; |
@@ -74,15 +83,18 @@ void IndexedSetter(uint32_t index, v8::Local<v8::Value> value, |
void IndexedQuery(uint32_t index, |
const v8::PropertyCallbackInfo<v8::Integer>& info) { |
+ CHECK(g_expect_interceptor_call); |
if (index == 7) info.GetReturnValue().Set(v8::DontDelete); |
} |
void IndexedDeleter(uint32_t index, |
const v8::PropertyCallbackInfo<v8::Boolean>& info) { |
+ CHECK(g_expect_interceptor_call); |
if (index == 7) info.GetReturnValue().Set(false); |
} |
void IndexedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { |
+ CHECK(g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
v8::Local<v8::Array> names = v8::Array::New(isolate, 1); |
@@ -98,12 +110,14 @@ bool AccessCheck(v8::Local<v8::Context> accessing_context, |
void GetCrossContextInt(v8::Local<v8::String> property, |
const v8::PropertyCallbackInfo<v8::Value>& info) { |
+ CHECK(!g_expect_interceptor_call); |
info.GetReturnValue().Set(g_cross_context_int); |
} |
void SetCrossContextInt(v8::Local<v8::String> property, |
v8::Local<v8::Value> value, |
const v8::PropertyCallbackInfo<void>& info) { |
+ CHECK(!g_expect_interceptor_call); |
v8::Isolate* isolate = info.GetIsolate(); |
v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
if (value->IsInt32()) { |
@@ -116,6 +130,57 @@ void Return42(v8::Local<v8::String> property, |
info.GetReturnValue().Set(42); |
} |
+void CheckCanRunScriptInContext(v8::Isolate* isolate, |
+ v8::Local<v8::Context> context) { |
+ v8::HandleScope handle_scope(isolate); |
+ v8::Context::Scope context_scope(context); |
+ |
+ g_expect_interceptor_call = false; |
+ g_cross_context_int = 0; |
+ |
+ // Running script in this context should work. |
+ CompileRunChecked(isolate, "this.foo = 42; this[23] = true;"); |
+ ExpectInt32("this.all_can_read", 42); |
+ CompileRunChecked(isolate, "this.cross_context_int = 23"); |
+ CHECK_EQ(g_cross_context_int, 23); |
+ ExpectInt32("this.cross_context_int", 23); |
+} |
+ |
+void CheckCrossContextAccess(v8::Isolate* isolate, |
+ v8::Local<v8::Context> accessing_context, |
+ v8::Local<v8::Object> accessed_object) { |
+ v8::HandleScope handle_scope(isolate); |
+ accessing_context->Global() |
+ ->Set(accessing_context, v8_str("other"), accessed_object) |
+ .FromJust(); |
+ v8::Context::Scope context_scope(accessing_context); |
+ |
+ g_expect_interceptor_call = true; |
+ g_cross_context_int = 23; |
+ |
+ { |
+ v8::TryCatch try_catch(isolate); |
+ CHECK(CompileRun(accessing_context, "this.other.foo").IsEmpty()); |
+ } |
+ { |
+ v8::TryCatch try_catch(isolate); |
+ CHECK(CompileRun(accessing_context, "this.other[23]").IsEmpty()); |
+ } |
+ |
+ // AllCanRead properties are also inaccessible. |
+ { |
+ v8::TryCatch try_catch(isolate); |
+ CHECK(CompileRun(accessing_context, "this.other.all_can_read").IsEmpty()); |
+ } |
+ |
+ // Intercepted properties are accessible, however. |
+ ExpectInt32("this.other.cross_context_int", 23); |
+ CompileRunChecked(isolate, "this.other.cross_context_int = 42"); |
+ ExpectInt32("this.other[7]", 42); |
+ ExpectString("JSON.stringify(Object.getOwnPropertyNames(this.other))", |
+ "[\"7\",\"cross_context_int\"]"); |
+} |
+ |
} // namespace |
TEST(AccessCheckWithInterceptor) { |
@@ -138,45 +203,76 @@ TEST(AccessCheckWithInterceptor) { |
v8::Local<v8::Context> context0 = |
v8::Context::New(isolate, nullptr, global_template); |
- context0->Enter(); |
- |
- // Running script in this context should work. |
- CompileRunChecked(isolate, "this.foo = 42; this[23] = true;"); |
- ExpectInt32("this.all_can_read", 42); |
- CompileRunChecked(isolate, "this.cross_context_int = 23"); |
- CHECK_EQ(g_cross_context_int, 23); |
- ExpectInt32("this.cross_context_int", 23); |
+ CheckCanRunScriptInContext(isolate, context0); |
// Create another context. |
+ v8::Local<v8::Context> context1 = |
+ v8::Context::New(isolate, nullptr, global_template); |
+ CheckCrossContextAccess(isolate, context1, context0->Global()); |
+} |
+ |
+TEST(NewRemoteContext) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<v8::ObjectTemplate> global_template = |
+ v8::ObjectTemplate::New(isolate); |
+ global_template->SetAccessCheckCallbackAndHandler( |
+ AccessCheck, |
+ v8::NamedPropertyHandlerConfiguration( |
+ NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator), |
+ v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter, |
+ IndexedQuery, IndexedDeleter, |
+ IndexedEnumerator)); |
+ global_template->SetNativeDataProperty( |
+ v8_str("cross_context_int"), GetCrossContextInt, SetCrossContextInt); |
+ global_template->SetNativeDataProperty( |
+ v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(), |
+ v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ); |
+ |
+ v8::Local<v8::Object> global0 = |
+ v8::Context::NewRemoteContext(isolate, global_template).ToLocalChecked(); |
+ |
+ // Create a real context. |
{ |
v8::HandleScope other_scope(isolate); |
v8::Local<v8::Context> context1 = |
v8::Context::New(isolate, nullptr, global_template); |
- context1->Global() |
- ->Set(context1, v8_str("other"), context0->Global()) |
- .FromJust(); |
- v8::Context::Scope context_scope(context1); |
- |
- { |
- v8::TryCatch try_catch(isolate); |
- CHECK(CompileRun(context1, "this.other.foo").IsEmpty()); |
- } |
- { |
- v8::TryCatch try_catch(isolate); |
- CHECK(CompileRun(context1, "this.other[23]").IsEmpty()); |
- } |
- |
- // AllCanRead properties are also inaccessible. |
- { |
- v8::TryCatch try_catch(isolate); |
- CHECK(CompileRun(context1, "this.other.all_can_read").IsEmpty()); |
- } |
- |
- // Intercepted properties are accessible, however. |
- ExpectInt32("this.other.cross_context_int", 23); |
- CompileRunChecked(isolate, "this.other.cross_context_int = 42"); |
- ExpectInt32("this.other[7]", 42); |
- ExpectString("JSON.stringify(Object.getOwnPropertyNames(this.other))", |
- "[\"7\",\"cross_context_int\"]"); |
+ |
+ CheckCrossContextAccess(isolate, context1, global0); |
+ } |
+ |
+ // Create a context using the detached global. |
+ { |
+ v8::HandleScope other_scope(isolate); |
+ v8::Local<v8::Context> context2 = |
+ v8::Context::New(isolate, nullptr, global_template, global0); |
+ |
+ CheckCanRunScriptInContext(isolate, context2); |
+ } |
+ |
+ // Turn a regular context into a remote context. |
+ { |
+ v8::HandleScope other_scope(isolate); |
+ v8::Local<v8::Context> context3 = |
+ v8::Context::New(isolate, nullptr, global_template); |
+ |
+ CheckCanRunScriptInContext(isolate, context3); |
+ |
+ // Turn the global object into a remote context, and try to access it. |
+ v8::Local<v8::Object> context3_global = context3->Global(); |
+ context3->DetachGlobal(); |
+ v8::Local<v8::Object> global3 = |
+ v8::Context::NewRemoteContext(isolate, global_template, context3_global) |
+ .ToLocalChecked(); |
+ v8::Local<v8::Context> context4 = |
+ v8::Context::New(isolate, nullptr, global_template); |
+ |
+ CheckCrossContextAccess(isolate, context4, global3); |
+ |
+ // Turn it back into a regular context. |
+ v8::Local<v8::Context> context5 = |
+ v8::Context::New(isolate, nullptr, global_template, global3); |
+ |
+ CheckCanRunScriptInContext(isolate, context5); |
} |
} |