Index: test/cctest/test-object-observe.cc |
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc |
index a8cbaf6ea75a49902e63bd75607fdc8860c62ca2..206ab66aa6873e9ca6e96905e2f13267403a2e65 100644 |
--- a/test/cctest/test-object-observe.cc |
+++ b/test/cctest/test-object-observe.cc |
@@ -442,36 +442,268 @@ static bool IndexedAccessAlwaysAllowed(Local<Object>, uint32_t, AccessType, |
} |
-static AccessType g_access_block_type = ACCESS_GET; |
-static const uint32_t kBlockedContextIndex = 1337; |
+static int TestObserveSecurity(Handle<Context> observer_context, |
+ Handle<Context> object_context, |
+ Handle<Context> mutation_context, |
+ bool use_access_checked_object = true) { |
+ Context::Scope observer_scope(observer_context); |
+ CompileRun("var records = null;" |
+ "var observer = function(r) { records = r };"); |
+ Handle<Value> observer = CompileRun("observer"); |
+ { |
+ Context::Scope object_scope(object_context); |
+ object_context->Global()->Set( |
+ String::NewFromUtf8(CcTest::isolate(), "observer"), observer); |
+ Handle<ObjectTemplate> tmpl = ObjectTemplate::New(CcTest::isolate()); |
+ if (use_access_checked_object) { |
+ tmpl->SetAccessCheckCallbacks(NamedAccessAlwaysAllowed, |
+ IndexedAccessAlwaysAllowed); |
+ } |
+ Handle<Object> obj = tmpl->NewInstance(); |
+ object_context->Global()->Set( |
+ String::NewFromUtf8(CcTest::isolate(), "obj"), obj); |
+ |
+ CompileRun("obj.length = 0;" |
+ "Object.observe(obj, observer," |
+ "['add', 'update', 'delete','reconfigure','splice']" |
+ ");"); |
+ { |
+ Context::Scope mutation_scope(mutation_context); |
+ mutation_context->Global()->Set( |
+ String::NewFromUtf8(CcTest::isolate(), "obj"), obj); |
+ CompileRun("obj.foo = 'bar';" |
+ "obj.foo = 'baz';" |
+ "delete obj.foo;" |
+ "Object.defineProperty(obj, 'bar', {value: 'bot'});" |
+ "Array.prototype.push.call(obj, 1, 2, 3);" |
+ "Array.prototype.splice.call(obj, 1, 2, 2, 4);" |
+ "Array.prototype.pop.call(obj);" |
+ "Array.prototype.shift.call(obj);"); |
+ } |
+ } |
+ return CompileRun("records ? records.length : 0")->Int32Value(); |
+} |
-static bool NamedAccessAllowUnlessBlocked(Local<Object> host, |
- Local<Value> key, |
- AccessType type, |
- Local<Value> data) { |
- if (type != g_access_block_type) return true; |
- v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>( |
- Utils::OpenHandle(*host)->GetIsolate()); |
- Handle<Object> global = isolate->GetCurrentContext()->Global(); |
- if (!global->Has(kBlockedContextIndex)) return true; |
- return !key->IsString() || !key->Equals(data); |
+ |
+TEST(ObserverSecurityAAA) { |
rossberg
2014/04/30 11:28:32
How about merging all these tests into a single on
|
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ CHECK_EQ(8, TestObserveSecurity(contextA, contextA, contextA)); |
} |
-static bool IndexedAccessAllowUnlessBlocked(Local<Object> host, |
- uint32_t index, |
- AccessType type, |
- Local<Value> data) { |
- if (type != g_access_block_type) return true; |
- v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>( |
- Utils::OpenHandle(*host)->GetIsolate()); |
- Handle<Object> global = isolate->GetCurrentContext()->Global(); |
- if (!global->Has(kBlockedContextIndex)) return true; |
- return index != data->Uint32Value(); |
+TEST(ObserverSecurityA1A2A3) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ |
+ v8::Local<Context> contextA1 = Context::New(isolate); |
+ v8::Local<Context> contextA2 = Context::New(isolate); |
+ v8::Local<Context> contextA3 = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextA1->SetSecurityToken(foo); |
+ contextA2->SetSecurityToken(foo); |
+ contextA3->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(8, TestObserveSecurity(contextA1, contextA2, contextA3)); |
+} |
+ |
+ |
+TEST(ObserverSecurityAAB) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ CHECK_EQ(0, TestObserveSecurity(contextA, contextA, contextB)); |
+} |
+ |
+ |
+TEST(ObserverSecurityA1A2B) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ |
+ v8::Local<Context> contextA1 = Context::New(isolate); |
+ v8::Local<Context> contextA2 = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextA1->SetSecurityToken(foo); |
+ contextA2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextA1, contextA2, contextB)); |
+} |
+ |
+ |
+TEST(ObserverSecurityABA) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ CHECK_EQ(0, TestObserveSecurity(contextA, contextB, contextA)); |
+} |
+ |
+ |
+TEST(ObserverSecurityA1BA2) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA1 = Context::New(isolate); |
+ v8::Local<Context> contextA2 = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextA1->SetSecurityToken(foo); |
+ contextA2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextA1, contextB, contextA2)); |
} |
+TEST(ObserverSecurityBA1A2) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA1 = Context::New(isolate); |
+ v8::Local<Context> contextA2 = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextA1->SetSecurityToken(foo); |
+ contextA2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextB, contextA1, contextA2)); |
+} |
+ |
+ |
+TEST(ObserverSecurityABB) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ CHECK_EQ(0, TestObserveSecurity(contextA, contextB, contextB)); |
+} |
+ |
+ |
+TEST(ObserverSecurityAB1B2) { |
rossberg
2014/04/30 11:28:32
How is this one different from BA1A2 above?
rafaelw
2014/05/02 03:22:32
yes. removed.
On 2014/04/30 11:28:32, rossberg wr
|
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB1 = Context::New(isolate); |
+ v8::Local<Context> contextB2 = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextB1->SetSecurityToken(foo); |
+ contextB2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextA, contextB1, contextB2)); |
+} |
+ |
+ |
+TEST(ObserverSecurityB1B2A) { |
rossberg
2014/04/30 11:28:32
And this seems to be the same as A1A2B.
rafaelw
2014/05/02 03:22:32
yes. removed.
On 2014/04/30 11:28:32, rossberg wr
|
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB1 = Context::New(isolate); |
+ v8::Local<Context> contextB2 = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextB1->SetSecurityToken(foo); |
+ contextB2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextB1, contextB2, contextA)); |
+} |
+ |
+ |
+TEST(ObserverSecurityBAB) { |
rossberg
2014/04/30 11:28:32
Same as ABA?
rafaelw
2014/05/02 03:22:32
yes. removed.
On 2014/04/30 11:28:32, rossberg wr
|
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ CHECK_EQ(0, TestObserveSecurity(contextB, contextA, contextB)); |
+} |
+ |
+ |
+TEST(ObserverSecurityB1AB2) { |
rossberg
2014/04/30 11:28:32
Same as A1BA2?
rafaelw
2014/05/02 03:22:32
yes. removed.
On 2014/04/30 11:28:32, rossberg wr
|
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB1 = Context::New(isolate); |
+ v8::Local<Context> contextB2 = Context::New(isolate); |
+ |
+ Local<Value> foo = v8_str("foo"); |
+ contextB1->SetSecurityToken(foo); |
+ contextB2->SetSecurityToken(foo); |
+ |
+ CHECK_EQ(0, TestObserveSecurity(contextB1, contextA, contextB2)); |
+} |
+ |
+ |
+TEST(ObserverSecurityNoAccessCheckOnObject) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ v8::Local<Context> contextC = Context::New(isolate); |
+ CHECK_EQ(8, TestObserveSecurity(contextA, contextB, contextC, false)); |
+} |
+ |
+ |
+TEST(ObserverSecurityNotify) { |
+ v8::Isolate* isolate = CcTest::isolate(); |
+ v8::HandleScope scope(isolate); |
+ v8::Local<Context> contextA = Context::New(isolate); |
+ v8::Local<Context> contextB = Context::New(isolate); |
+ |
+ Context::Scope scopeA(contextA); |
+ Handle<ObjectTemplate> tmpl = ObjectTemplate::New(CcTest::isolate()); |
+ tmpl->SetAccessCheckCallbacks(NamedAccessAlwaysAllowed, |
+ IndexedAccessAlwaysAllowed); |
+ Handle<Object> obj = tmpl->NewInstance(); |
+ contextA->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), obj); |
+ |
+ CompileRun("var recordsA = null;" |
+ "var observerA = function(r) { recordsA = r };" |
+ "Object.observe(obj, observerA);"); |
+ |
+ { |
+ Context::Scope scopeB(contextB); |
+ contextB->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), obj); |
+ CompileRun("var recordsB = null;" |
+ "var observerB = function(r) { recordsB = r };" |
+ "Object.observe(obj, observerB);"); |
+ } |
+ |
+ CompileRun("var notifier = Object.getNotifier(obj);" |
+ "notifier.notify({ type: 'update' });"); |
+ CHECK_EQ(1, CompileRun("recordsA ? recordsA.length : 0")->Int32Value()); |
+ |
+ { |
+ Context::Scope scopeB(contextB); |
+ CHECK_EQ(0, CompileRun("recordsB ? recordsB.length : 0")->Int32Value()); |
+ } |
+} |
+ |
+ |
+TEST(HiddenPropertiesLeakage) { |
+ HandleScope scope(CcTest::isolate()); |
+ LocalContext context(CcTest::isolate()); |
+ CompileRun("var obj = {};" |
+ "var records = null;" |
+ "var observer = function(r) { records = r };" |
+ "Object.observe(obj, observer);"); |
+ Handle<Value> obj = |
+ context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj")); |
+ Handle<Object>::Cast(obj) |
+ ->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"), |
+ Null(CcTest::isolate())); |
+ CompileRun(""); // trigger delivery |
+ CHECK(CompileRun("records")->IsNull()); |
+} |
+ |
+ |
+static const uint32_t kBlockedContextIndex = 1337; |
+ |
+ |
static bool BlockAccessKeys(Local<Object> host, Local<Value> key, |
AccessType type, Local<Value>) { |
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>( |
@@ -496,234 +728,67 @@ static Handle<Object> CreateAccessCheckedObject( |
} |
-TEST(NamedAccessCheck) { |
- const AccessType types[] = { ACCESS_GET, ACCESS_HAS }; |
- for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { |
- HandleScope scope(CcTest::isolate()); |
- LocalContext context(CcTest::isolate()); |
- g_access_block_type = types[i]; |
- Handle<Object> instance = CreateAccessCheckedObject( |
- CcTest::isolate(), |
- NamedAccessAllowUnlessBlocked, |
- IndexedAccessAlwaysAllowed, |
- String::NewFromUtf8(CcTest::isolate(), "foo")); |
- CompileRun("var records = null;" |
- "var objNoCheck = {};" |
- "var observer = function(r) { records = r };" |
- "Object.observe(obj, observer);" |
- "Object.observe(objNoCheck, observer);"); |
- Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
- { |
- LocalContext context2(CcTest::isolate()); |
- context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
- instance); |
- context2->Global()->Set( |
- String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), |
- obj_no_check); |
- CompileRun("var records2 = null;" |
- "var observer2 = function(r) { records2 = r };" |
- "Object.observe(obj, observer2);" |
- "Object.observe(objNoCheck, observer2);" |
- "obj.foo = 'bar';" |
- "Object.defineProperty(obj, 'foo', {value: 5});" |
- "Object.defineProperty(obj, 'foo', {get: function(){}});" |
- "obj.bar = 'baz';" |
- "objNoCheck.baz = 'quux'"); |
- const RecordExpectation expected_records2[] = { |
- { instance, "add", "foo", Handle<Value>() }, |
- { instance, "update", "foo", |
- String::NewFromUtf8(CcTest::isolate(), "bar") }, |
- { instance, "reconfigure", "foo", |
- Number::New(CcTest::isolate(), 5) }, |
- { instance, "add", "bar", Handle<Value>() }, |
- { obj_no_check, "add", "baz", Handle<Value>() }, |
- }; |
- EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
- } |
- const RecordExpectation expected_records[] = { |
- { instance, "add", "bar", Handle<Value>() }, |
- { obj_no_check, "add", "baz", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records"), expected_records); |
- } |
-} |
- |
- |
-TEST(IndexedAccessCheck) { |
- const AccessType types[] = { ACCESS_GET, ACCESS_HAS }; |
- for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { |
- HandleScope scope(CcTest::isolate()); |
- LocalContext context(CcTest::isolate()); |
- g_access_block_type = types[i]; |
- Handle<Object> instance = CreateAccessCheckedObject( |
- CcTest::isolate(), NamedAccessAlwaysAllowed, |
- IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 7)); |
- CompileRun("var records = null;" |
- "var objNoCheck = {};" |
- "var observer = function(r) { records = r };" |
- "Object.observe(obj, observer);" |
- "Object.observe(objNoCheck, observer);"); |
- Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
- { |
- LocalContext context2(CcTest::isolate()); |
- context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
- instance); |
- context2->Global()->Set( |
- String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), |
- obj_no_check); |
- CompileRun("var records2 = null;" |
- "var observer2 = function(r) { records2 = r };" |
- "Object.observe(obj, observer2);" |
- "Object.observe(objNoCheck, observer2);" |
- "obj[7] = 'foo';" |
- "Object.defineProperty(obj, '7', {value: 5});" |
- "Object.defineProperty(obj, '7', {get: function(){}});" |
- "obj[8] = 'bar';" |
- "objNoCheck[42] = 'quux'"); |
- const RecordExpectation expected_records2[] = { |
- { instance, "add", "7", Handle<Value>() }, |
- { instance, "update", "7", |
- String::NewFromUtf8(CcTest::isolate(), "foo") }, |
- { instance, "reconfigure", "7", Number::New(CcTest::isolate(), 5) }, |
- { instance, "add", "8", Handle<Value>() }, |
- { obj_no_check, "add", "42", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
- } |
- const RecordExpectation expected_records[] = { |
- { instance, "add", "8", Handle<Value>() }, |
- { obj_no_check, "add", "42", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records"), expected_records); |
- } |
-} |
- |
- |
-TEST(SpliceAccessCheck) { |
+TEST(GetNotifierFromOtherContext) { |
HandleScope scope(CcTest::isolate()); |
LocalContext context(CcTest::isolate()); |
- g_access_block_type = ACCESS_GET; |
Handle<Object> instance = CreateAccessCheckedObject( |
- CcTest::isolate(), NamedAccessAlwaysAllowed, |
- IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 1)); |
- CompileRun("var records = null;" |
- "obj[1] = 'foo';" |
- "obj.length = 2;" |
- "var objNoCheck = {1: 'bar', length: 2};" |
- "observer = function(r) { records = r };" |
- "Array.observe(obj, observer);" |
- "Array.observe(objNoCheck, observer);"); |
- Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
+ CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed); |
{ |
LocalContext context2(CcTest::isolate()); |
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
instance); |
- context2->Global()->Set( |
- String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check); |
- CompileRun("var records2 = null;" |
- "var observer2 = function(r) { records2 = r };" |
- "Array.observe(obj, observer2);" |
- "Array.observe(objNoCheck, observer2);" |
- // No one should hear about this: no splice records are emitted |
- // for access-checked objects |
- "[].push.call(obj, 5);" |
- "[].splice.call(obj, 1, 1);" |
- "[].pop.call(obj);" |
- "[].pop.call(objNoCheck);"); |
- // TODO(adamk): Extend EXPECT_RECORDS to be able to assert more things |
- // about splice records. For this test it's not so important since |
- // we just want to guarantee the machinery is in operation at all. |
- const RecordExpectation expected_records2[] = { |
- { obj_no_check, "splice", "", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
+ CHECK(CompileRun("Object.getNotifier(obj)")->IsNull()); |
} |
- const RecordExpectation expected_records[] = { |
- { obj_no_check, "splice", "", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records"), expected_records); |
} |
-TEST(DisallowAllForAccessKeys) { |
+TEST(GetNotifierFromOtherOrigin) { |
HandleScope scope(CcTest::isolate()); |
+ Handle<Value> foo = String::NewFromUtf8(CcTest::isolate(), "foo"); |
+ Handle<Value> bar = String::NewFromUtf8(CcTest::isolate(), "bar"); |
LocalContext context(CcTest::isolate()); |
+ context->SetSecurityToken(foo); |
Handle<Object> instance = CreateAccessCheckedObject( |
CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed); |
- CompileRun("var records = null;" |
- "var objNoCheck = {};" |
- "var observer = function(r) { records = r };" |
- "Object.observe(obj, observer);" |
- "Object.observe(objNoCheck, observer);"); |
- Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
+ |
{ |
LocalContext context2(CcTest::isolate()); |
+ context2->SetSecurityToken(bar); |
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
instance); |
- context2->Global()->Set( |
- String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check); |
- CompileRun("var records2 = null;" |
- "var observer2 = function(r) { records2 = r };" |
- "Object.observe(obj, observer2);" |
- "Object.observe(objNoCheck, observer2);" |
- "obj.foo = 'bar';" |
- "obj[5] = 'baz';" |
- "objNoCheck.baz = 'quux'"); |
- const RecordExpectation expected_records2[] = { |
- { instance, "add", "foo", Handle<Value>() }, |
- { instance, "add", "5", Handle<Value>() }, |
- { obj_no_check, "add", "baz", Handle<Value>() }, |
- }; |
- EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
+ CHECK(CompileRun("Object.getNotifier(obj)")->IsNull()); |
} |
- const RecordExpectation expected_records[] = { |
- { obj_no_check, "add", "baz", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records"), expected_records); |
} |
-TEST(AccessCheckDisallowApiModifications) { |
+TEST(GetNotifierFromSameOrigin) { |
HandleScope scope(CcTest::isolate()); |
+ Handle<Value> foo = String::NewFromUtf8(CcTest::isolate(), "foo"); |
LocalContext context(CcTest::isolate()); |
+ context->SetSecurityToken(foo); |
Handle<Object> instance = CreateAccessCheckedObject( |
CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed); |
- CompileRun("var records = null;" |
- "var observer = function(r) { records = r };" |
- "Object.observe(obj, observer);"); |
+ |
{ |
LocalContext context2(CcTest::isolate()); |
+ context2->SetSecurityToken(foo); |
context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
instance); |
- CompileRun("var records2 = null;" |
- "var observer2 = function(r) { records2 = r };" |
- "Object.observe(obj, observer2);"); |
- instance->Set(5, String::NewFromUtf8(CcTest::isolate(), "bar")); |
- instance->Set(String::NewFromUtf8(CcTest::isolate(), "foo"), |
- String::NewFromUtf8(CcTest::isolate(), "bar")); |
- CompileRun(""); // trigger delivery |
- const RecordExpectation expected_records2[] = { |
- { instance, "add", "5", Handle<Value>() }, |
- { instance, "add", "foo", Handle<Value>() } |
- }; |
- EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
+ CHECK(CompileRun("Object.getNotifier(obj)")->IsObject()); |
} |
- CHECK(CompileRun("records")->IsNull()); |
} |
-TEST(HiddenPropertiesLeakage) { |
+// This case should never happen in a well-behaved embedder, but there's |
+// no way for V8 to prevent and API user from doing it. |
rossberg
2014/04/30 11:28:32
Typo: s/and/an/
rafaelw
2014/05/02 03:22:32
Test & comment removed.
On 2014/04/30 11:28:32,
|
+TEST(GetNotifierFromOtherContextWithoutAccessChecks) { |
HandleScope scope(CcTest::isolate()); |
LocalContext context(CcTest::isolate()); |
- CompileRun("var obj = {};" |
- "var records = null;" |
- "var observer = function(r) { records = r };" |
- "Object.observe(obj, observer);"); |
- Handle<Value> obj = |
- context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj")); |
- Handle<Object>::Cast(obj) |
- ->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"), |
- Null(CcTest::isolate())); |
- CompileRun(""); // trigger delivery |
- CHECK(CompileRun("records")->IsNull()); |
+ Handle<Object> instance = Object::New(CcTest::isolate()); |
+ { |
+ LocalContext context2(CcTest::isolate()); |
+ context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), |
+ instance); |
+ CHECK(CompileRun("Object.getNotifier(obj)")->IsObject()); |
+ } |
} |