Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 4246) |
+++ test/cctest/test-api.cc (working copy) |
@@ -4465,7 +4465,7 @@ |
// Enter env2 |
env2->Enter(); |
- // Create a function in env1 |
+ // Create a function in env2 and add a reference to it in env1. |
Local<v8::Object> global2 = env2->Global(); |
global2->Set(v8_str("prop"), v8::Integer::New(1)); |
CompileRun("function getProp() {return prop;}"); |
@@ -4473,7 +4473,7 @@ |
env1->Global()->Set(v8_str("getProp"), |
global2->Get(v8_str("getProp"))); |
- // Detach env1's global, and reuse the global object of env1 |
+ // Detach env2's global, and reuse the global object of env2 |
env2->Exit(); |
env2->DetachGlobal(); |
// env2 has a new global object. |
@@ -4513,6 +4513,85 @@ |
} |
+TEST(DetachAndReattachGlobal) { |
+ v8::HandleScope scope; |
+ LocalContext env1; |
+ |
+ // Create second environment. |
+ v8::Persistent<Context> env2 = Context::New(); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ |
+ // Set same security token for env1 and env2. |
+ env1->SetSecurityToken(foo); |
+ env2->SetSecurityToken(foo); |
+ |
+ // Create a property on the global object in env2. |
+ { |
+ v8::Context::Scope scope(env2); |
+ env2->Global()->Set(v8_str("p"), v8::Integer::New(42)); |
+ } |
+ |
+ // Create a reference to env2 global from env1 global. |
+ env1->Global()->Set(v8_str("other"), env2->Global()); |
+ |
+ // Check that we have access to other.p in env2 from env1. |
+ Local<Value> result = CompileRun("other.p"); |
+ CHECK(result->IsInt32()); |
+ CHECK_EQ(42, result->Int32Value()); |
+ |
+ // Hold on to global from env2 and detach global from env2. |
+ Local<v8::Object> global2 = env2->Global(); |
+ env2->DetachGlobal(); |
+ |
+ // Check that the global has been detached. No other.p property can |
+ // be found. |
+ result = CompileRun("other.p"); |
+ CHECK(result->IsUndefined()); |
+ |
+ // Reuse global2 for env3. |
+ v8::Persistent<Context> env3 = |
+ Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2); |
+ CHECK_EQ(global2, env3->Global()); |
+ |
+ // Start by using the same security token for env3 as for env1 and env2. |
+ env3->SetSecurityToken(foo); |
+ |
+ // Create a property on the global object in env3. |
+ { |
+ v8::Context::Scope scope(env3); |
+ env3->Global()->Set(v8_str("p"), v8::Integer::New(24)); |
+ } |
+ |
+ // Check that other.p is now the property in env3 and that we have access. |
+ result = CompileRun("other.p"); |
+ CHECK(result->IsInt32()); |
+ CHECK_EQ(24, result->Int32Value()); |
+ |
+ // Change security token for env3 to something different from env1 and env2. |
+ env3->SetSecurityToken(v8_str("bar")); |
+ |
+ // Check that we do not have access to other.p in env1. |other| is now |
+ // the global object for env3 which has a different security token, |
+ // so access should be blocked. |
+ result = CompileRun("other.p"); |
+ CHECK(result->IsUndefined()); |
+ |
+ // Detach the global for env3 and reattach it to env2. |
+ env3->DetachGlobal(); |
+ env2->ReattachGlobal(global2); |
+ |
+ // Check that we have access to other.p again in env1. |other| is now |
+ // the global object for env2 which has the same security token as env1. |
+ result = CompileRun("other.p"); |
+ CHECK(result->IsInt32()); |
+ CHECK_EQ(42, result->Int32Value()); |
+ |
+ env2.Dispose(); |
+ env3.Dispose(); |
+} |
+ |
+ |
static bool NamedAccessBlocker(Local<v8::Object> global, |
Local<Value> name, |
v8::AccessType type, |