Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index aeb4cbe52298bd2a0751fbc60e3e1cf2fac55c39..def80fd93abe5c26450d37ae0b170a679a5fc9e3 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -14937,3 +14937,112 @@ THREADED_TEST(Regress1516) { |
} |
} |
} |
+ |
+ |
+static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, |
+ Local<Value> name, |
+ v8::AccessType type, |
+ Local<Value> data) { |
+ // Only block read access to __proto__. |
+ if (type == v8::ACCESS_GET && |
+ name->IsString() && |
+ name->ToString()->Length() == 9 && |
+ name->ToString()->Utf8Length() == 9) { |
+ char buffer[10]; |
+ CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); |
+ return strncmp(buffer, "__proto__", 9) != 0; |
+ } |
+ |
+ return true; |
+} |
+ |
+ |
+THREADED_TEST(Regress93759) { |
+ HandleScope scope; |
+ |
+ // Template for object with security check. |
+ Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(); |
+ // We don't do indexing, so any callback can be used for that. |
+ no_proto_template->SetAccessCheckCallbacks( |
+ BlockProtoNamedSecurityTestCallback, |
+ IndexedSecurityTestCallback); |
+ |
+ // Templates for objects with hidden prototypes and possibly security check. |
+ Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New(); |
+ hidden_proto_template->SetHiddenPrototype(true); |
+ |
+ Local<FunctionTemplate> protected_hidden_proto_template = |
+ v8::FunctionTemplate::New(); |
+ protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( |
+ BlockProtoNamedSecurityTestCallback, |
+ IndexedSecurityTestCallback); |
+ protected_hidden_proto_template->SetHiddenPrototype(true); |
+ |
+ // Context for "foreign" objects used in test. |
+ Persistent<Context> context = v8::Context::New(); |
+ context->Enter(); |
+ |
+ // Plain object, no security check. |
+ Local<Object> simple_object = Object::New(); |
+ |
+ // Object with explicit security check. |
+ Local<Object> protected_object = |
+ no_proto_template->NewInstance(); |
+ |
+ // JSGlobalProxy object, always have security check. |
+ Local<Object> proxy_object = |
+ context->Global(); |
+ |
+ // Global object, the prototype of proxy_object. No security checks. |
+ Local<Object> global_object = |
+ proxy_object->GetPrototype()->ToObject(); |
+ |
+ // Hidden prototype without security check. |
+ Local<Object> hidden_prototype = |
+ hidden_proto_template->GetFunction()->NewInstance(); |
+ Local<Object> object_with_hidden = |
+ Object::New(); |
+ object_with_hidden->SetPrototype(hidden_prototype); |
+ |
+ // Hidden prototype with security check on the hidden prototype. |
+ Local<Object> protected_hidden_prototype = |
+ protected_hidden_proto_template->GetFunction()->NewInstance(); |
+ Local<Object> object_with_protected_hidden = |
+ Object::New(); |
+ object_with_protected_hidden->SetPrototype(protected_hidden_prototype); |
+ |
+ context->Exit(); |
+ |
+ // Template for object for second context. Values to test are put on it as |
+ // properties. |
+ Local<ObjectTemplate> global_template = ObjectTemplate::New(); |
+ global_template->Set(v8_str("simple"), simple_object); |
+ global_template->Set(v8_str("protected"), protected_object); |
+ global_template->Set(v8_str("global"), global_object); |
+ global_template->Set(v8_str("proxy"), proxy_object); |
+ global_template->Set(v8_str("hidden"), object_with_hidden); |
+ global_template->Set(v8_str("phidden"), object_with_protected_hidden); |
+ |
+ LocalContext context2(NULL, global_template); |
+ |
+ Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); |
+ CHECK(result1->Equals(simple_object->GetPrototype())); |
+ |
+ Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); |
+ CHECK(result2->Equals(Undefined())); |
+ |
+ Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); |
+ CHECK(result3->Equals(global_object->GetPrototype())); |
+ |
+ Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); |
+ CHECK(result4->Equals(Undefined())); |
+ |
+ Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); |
+ CHECK(result5->Equals( |
+ object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); |
+ |
+ Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); |
+ CHECK(result6->Equals(Undefined())); |
+ |
+ context.Dispose(); |
+} |