Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index 13c21e1b5769dfff097037e258cffb1ab494607b..43a243def444f0376c34e95f961ec5a252c80080 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -19787,12 +19787,59 @@ TEST(JSONStringifyAccessCheck) { |
} |
-TEST(Bug2778) { |
- // Check that Object.observe includes access check. |
- i::FLAG_harmony_observation = true; |
+bool access_check_fail_thrown = false; |
+bool catch_callback_called = false; |
+ |
+ |
+// Failed access check callback that performs a GC on each invocation. |
+void FailedAccessCheckThrows(Local<v8::Object> target, |
+ v8::AccessType type, |
+ Local<v8::Value> data) { |
+ access_check_fail_thrown = true; |
+ i::PrintF("Access check failed. Error thrown.\n"); |
+ v8::ThrowException(v8::Exception::Error(v8_str("cross context"))); |
+} |
+ |
+ |
+void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { |
+ for (int i = 0; i < args.Length(); i++) { |
+ i::PrintF("%s\n", *String::Utf8Value(args[i])); |
+ } |
+ catch_callback_called = true; |
+} |
+ |
+ |
+void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { |
+ args[0]->ToObject()->HasOwnProperty(args[1]->ToString()); |
+} |
+ |
+ |
+void CheckCorrectThrow(const char* script) { |
+ // Test that the script, when wrapped into a try-catch, triggers the catch |
+ // clause due to failed access check throwing an exception. |
+ // The subsequent try-catch should run without any exception. |
+ access_check_fail_thrown = false; |
+ catch_callback_called = false; |
+ i::ScopedVector<char> source(1024); |
+ i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); |
+ CompileRun(source.start()); |
+ CHECK(access_check_fail_thrown); |
+ CHECK(catch_callback_called); |
+ |
+ access_check_fail_thrown = false; |
+ catch_callback_called = false; |
+ CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); |
+ CHECK(!access_check_fail_thrown); |
+ CHECK(!catch_callback_called); |
+} |
+ |
+ |
+TEST(AccessCheckThrows) { |
+ i::FLAG_allow_natives_syntax = true; |
v8::V8::Initialize(); |
- v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
- v8::HandleScope scope(isolate); |
+ v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); |
+ v8::HandleScope scope(v8::Isolate::GetCurrent()); |
+ |
// Create an ObjectTemplate for global objects and install access |
// check callbacks that will block access. |
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
@@ -19800,25 +19847,48 @@ TEST(Bug2778) { |
IndexAccessAlwaysBlocked); |
// Create a context and set an x property on it's global object. |
- LocalContext outer_context(NULL, global_template); |
- v8::Handle<v8::Object> outer_global = outer_context->Global(); |
- outer_global->Set(v8_str("x"), v8_num(42)); |
+ LocalContext context0(NULL, global_template); |
+ context0->Global()->Set(v8_str("x"), v8_num(42)); |
+ v8::Handle<v8::Object> global0 = context0->Global(); |
- // Enter a new context. |
- v8::Handle<v8::Context> inner_context = v8::Context::New(isolate); |
- { v8::Context::Scope inner(inner_context); |
- v8::Handle<v8::Object> inner_global = inner_context->Global(); |
- inner_global->Set(v8_str("other"), outer_global); |
- v8::Handle<v8::FunctionTemplate> unreachable = |
- v8::FunctionTemplate::New(UnreachableCallback); |
- inner_global->Set(v8_str("unreachable"), unreachable->GetFunction()); |
- ExpectUndefined("other.x"); // Verify that access checks are in place. |
- CompileRun("Object.observe(other, unreachable);"); // Install observer. |
- } |
- |
- ExpectInt32("x", 42); |
- // This must not be observable by the observer set up in the inner context. |
- CompileRun("var a = 123;"); |
+ // Create a context with a different security token so that the |
+ // failed access check callback will be called on each access. |
+ LocalContext context1(NULL, global_template); |
+ context1->Global()->Set(v8_str("other"), global0); |
+ |
+ v8::Handle<v8::FunctionTemplate> catcher_fun = |
+ v8::FunctionTemplate::New(CatcherCallback); |
+ context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction()); |
+ |
+ v8::Handle<v8::FunctionTemplate> has_own_property_fun = |
+ v8::FunctionTemplate::New(HasOwnPropertyCallback); |
+ context1->Global()->Set(v8_str("has_own_property"), |
+ has_own_property_fun->GetFunction()); |
+ |
+ { v8::TryCatch try_catch; |
+ access_check_fail_thrown = false; |
+ CompileRun("other.x;"); |
+ CHECK(access_check_fail_thrown); |
+ CHECK(try_catch.HasCaught()); |
+ } |
+ |
+ CheckCorrectThrow("other.x"); |
+ CheckCorrectThrow("other[1]"); |
+ CheckCorrectThrow("JSON.stringify(other)"); |
+ CheckCorrectThrow("has_own_property(other, 'x')"); |
+ CheckCorrectThrow("%GetProperty(other, 'x')"); |
+ CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)"); |
+ CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')"); |
+ CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); |
+ CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); |
+ CheckCorrectThrow("%HasLocalProperty(other, 'x')"); |
+ CheckCorrectThrow("%HasProperty(other, 'x')"); |
+ CheckCorrectThrow("%HasElement(other, 1)"); |
+ CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); |
+ CheckCorrectThrow("%GetPropertyNames(other)"); |
+ CheckCorrectThrow("%GetLocalPropertyNames(other, true)"); |
+ CheckCorrectThrow("%DefineOrRedefineAccessorProperty(" |
+ "other, 'x', null, null, 1)"); |
} |
#endif // WIN32 |