Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: test/cctest/test-object-observe.cc

Issue 265503002: Re-enable Object.observe and add enforcement for security invariants. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: cr comment Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/cctest/cctest.status ('k') | test/mjsunit/es7/object-observe.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 18 matching lines...) Expand all
29 29
30 #include "cctest.h" 30 #include "cctest.h"
31 31
32 using namespace v8; 32 using namespace v8;
33 namespace i = v8::internal; 33 namespace i = v8::internal;
34 34
35 35
36 TEST(PerIsolateState) { 36 TEST(PerIsolateState) {
37 HandleScope scope(CcTest::isolate()); 37 HandleScope scope(CcTest::isolate());
38 LocalContext context1(CcTest::isolate()); 38 LocalContext context1(CcTest::isolate());
39
40 Local<Value> foo = v8_str("foo");
41 context1->SetSecurityToken(foo);
42
39 CompileRun( 43 CompileRun(
40 "var count = 0;" 44 "var count = 0;"
41 "var calls = 0;" 45 "var calls = 0;"
42 "var observer = function(records) { count = records.length; calls++ };" 46 "var observer = function(records) { count = records.length; calls++ };"
43 "var obj = {};" 47 "var obj = {};"
44 "Object.observe(obj, observer);"); 48 "Object.observe(obj, observer);");
45 Handle<Value> observer = CompileRun("observer"); 49 Handle<Value> observer = CompileRun("observer");
46 Handle<Value> obj = CompileRun("obj"); 50 Handle<Value> obj = CompileRun("obj");
47 Handle<Value> notify_fun1 = CompileRun( 51 Handle<Value> notify_fun1 = CompileRun(
48 "(function() { obj.foo = 'bar'; })"); 52 "(function() { obj.foo = 'bar'; })");
49 Handle<Value> notify_fun2; 53 Handle<Value> notify_fun2;
50 { 54 {
51 LocalContext context2(CcTest::isolate()); 55 LocalContext context2(CcTest::isolate());
56 context2->SetSecurityToken(foo);
52 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 57 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
53 obj); 58 obj);
54 notify_fun2 = CompileRun( 59 notify_fun2 = CompileRun(
55 "(function() { obj.foo = 'baz'; })"); 60 "(function() { obj.foo = 'baz'; })");
56 } 61 }
57 Handle<Value> notify_fun3; 62 Handle<Value> notify_fun3;
58 { 63 {
59 LocalContext context3(CcTest::isolate()); 64 LocalContext context3(CcTest::isolate());
65 context3->SetSecurityToken(foo);
60 context3->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 66 context3->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
61 obj); 67 obj);
62 notify_fun3 = CompileRun( 68 notify_fun3 = CompileRun(
63 "(function() { obj.foo = 'bat'; })"); 69 "(function() { obj.foo = 'bat'; })");
64 } 70 }
65 { 71 {
66 LocalContext context4(CcTest::isolate()); 72 LocalContext context4(CcTest::isolate());
73 context4->SetSecurityToken(foo);
67 context4->Global()->Set( 74 context4->Global()->Set(
68 String::NewFromUtf8(CcTest::isolate(), "observer"), observer); 75 String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
69 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun1"), 76 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun1"),
70 notify_fun1); 77 notify_fun1);
71 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun2"), 78 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun2"),
72 notify_fun2); 79 notify_fun2);
73 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun3"), 80 context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun3"),
74 notify_fun3); 81 notify_fun3);
75 CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)"); 82 CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)");
76 } 83 }
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 " Object.observe(objArr[objArr.length-1], function(){});" 209 " Object.observe(objArr[objArr.length-1], function(){});"
203 "}" 210 "}"
204 "Object.observe(obj, observer);"); 211 "Object.observe(obj, observer);");
205 } 212 }
206 // obj is now marked "is_observed", but our map has moved. 213 // obj is now marked "is_observed", but our map has moved.
207 CompileRun("obj.foo = 'bar'"); 214 CompileRun("obj.foo = 'bar'");
208 CHECK(CompileRun("ran")->BooleanValue()); 215 CHECK(CompileRun("ran")->BooleanValue());
209 } 216 }
210 217
211 218
212 TEST(GlobalObjectObservation) {
213 LocalContext context(CcTest::isolate());
214 HandleScope scope(CcTest::isolate());
215 Handle<Object> global_proxy = context->Global();
216 CompileRun(
217 "var records = [];"
218 "var global = this;"
219 "Object.observe(global, function(r) { [].push.apply(records, r) });"
220 "global.foo = 'hello';");
221 CHECK_EQ(1, CompileRun("records.length")->Int32Value());
222 CHECK(global_proxy->StrictEquals(CompileRun("records[0].object")));
223
224 // Detached, mutating the proxy has no effect.
225 context->DetachGlobal();
226 CompileRun("global.bar = 'goodbye';");
227 CHECK_EQ(1, CompileRun("records.length")->Int32Value());
228 CompileRun("this.baz = 'goodbye';");
229 CHECK_EQ(1, CompileRun("records.length")->Int32Value());
230
231 // Attached to a different context, should not leak mutations
232 // to the old context.
233 context->DetachGlobal();
234 {
235 LocalContext context2(CcTest::isolate());
236 CompileRun(
237 "var records2 = [];"
238 "var global = this;"
239 "Object.observe(this, function(r) { [].push.apply(records2, r) });"
240 "this.v1 = 'context2';");
241 context2->DetachGlobal();
242 CompileRun(
243 "global.v2 = 'context2';"
244 "this.v3 = 'context2';");
245 CHECK_EQ(1, CompileRun("records2.length")->Int32Value());
246 }
247 CHECK_EQ(1, CompileRun("records.length")->Int32Value());
248
249 // Attaching by passing to Context::New
250 {
251 // Delegates to Context::New
252 LocalContext context3(
253 CcTest::isolate(), NULL, Handle<ObjectTemplate>(), global_proxy);
254 CompileRun(
255 "var records3 = [];"
256 "Object.observe(this, function(r) { [].push.apply(records3, r) });"
257 "this.qux = 'context3';");
258 CHECK_EQ(1, CompileRun("records3.length")->Int32Value());
259 CHECK(global_proxy->StrictEquals(CompileRun("records3[0].object")));
260 }
261 CHECK_EQ(1, CompileRun("records.length")->Int32Value());
262 }
263
264
265 struct RecordExpectation { 219 struct RecordExpectation {
266 Handle<Value> object; 220 Handle<Value> object;
267 const char* type; 221 const char* type;
268 const char* name; 222 const char* name;
269 Handle<Value> old_value; 223 Handle<Value> old_value;
270 }; 224 };
271 225
272 226
273 // TODO(adamk): Use this helper elsewhere in this file. 227 // TODO(adamk): Use this helper elsewhere in this file.
274 static void ExpectRecords(v8::Isolate* isolate, 228 static void ExpectRecords(v8::Isolate* isolate,
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 CHECK_EQ(1, NumberOfElements(callbackInfoMap)); 377 CHECK_EQ(1, NumberOfElements(callbackInfoMap));
424 CHECK_EQ(1, NumberOfElements(objectInfoMap)); 378 CHECK_EQ(1, NumberOfElements(objectInfoMap));
425 CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap)); 379 CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap));
426 i_isolate->heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 380 i_isolate->heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
427 CHECK_EQ(0, NumberOfElements(callbackInfoMap)); 381 CHECK_EQ(0, NumberOfElements(callbackInfoMap));
428 CHECK_EQ(0, NumberOfElements(objectInfoMap)); 382 CHECK_EQ(0, NumberOfElements(objectInfoMap));
429 CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap)); 383 CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap));
430 } 384 }
431 385
432 386
433 static bool NamedAccessAlwaysAllowed(Local<Object>, Local<Value>, AccessType, 387 static int TestObserveSecurity(Handle<Context> observer_context,
434 Local<Value>) { 388 Handle<Context> object_context,
435 return true; 389 Handle<Context> mutation_context) {
436 } 390 Context::Scope observer_scope(observer_context);
437 391 CompileRun("var records = null;"
438 392 "var observer = function(r) { records = r };");
439 static bool IndexedAccessAlwaysAllowed(Local<Object>, uint32_t, AccessType, 393 Handle<Value> observer = CompileRun("observer");
440 Local<Value>) { 394 {
441 return true; 395 Context::Scope object_scope(object_context);
442 } 396 object_context->Global()->Set(
443 397 String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
444 398 CompileRun("var obj = {};"
445 static AccessType g_access_block_type = ACCESS_GET; 399 "obj.length = 0;"
446 static const uint32_t kBlockedContextIndex = 1337; 400 "Object.observe(obj, observer,"
447 401 "['add', 'update', 'delete','reconfigure','splice']"
448 402 ");");
449 static bool NamedAccessAllowUnlessBlocked(Local<Object> host, 403 Handle<Value> obj = CompileRun("obj");
450 Local<Value> key,
451 AccessType type,
452 Local<Value> data) {
453 if (type != g_access_block_type) return true;
454 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(
455 Utils::OpenHandle(*host)->GetIsolate());
456 Handle<Object> global = isolate->GetCurrentContext()->Global();
457 if (!global->Has(kBlockedContextIndex)) return true;
458 return !key->IsString() || !key->Equals(data);
459 }
460
461
462 static bool IndexedAccessAllowUnlessBlocked(Local<Object> host,
463 uint32_t index,
464 AccessType type,
465 Local<Value> data) {
466 if (type != g_access_block_type) return true;
467 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(
468 Utils::OpenHandle(*host)->GetIsolate());
469 Handle<Object> global = isolate->GetCurrentContext()->Global();
470 if (!global->Has(kBlockedContextIndex)) return true;
471 return index != data->Uint32Value();
472 }
473
474
475 static bool BlockAccessKeys(Local<Object> host, Local<Value> key,
476 AccessType type, Local<Value>) {
477 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(
478 Utils::OpenHandle(*host)->GetIsolate());
479 Handle<Object> global = isolate->GetCurrentContext()->Global();
480 return type != ACCESS_KEYS || !global->Has(kBlockedContextIndex);
481 }
482
483
484 static Handle<Object> CreateAccessCheckedObject(
485 v8::Isolate* isolate,
486 NamedSecurityCallback namedCallback,
487 IndexedSecurityCallback indexedCallback,
488 Handle<Value> data = Handle<Value>()) {
489 Handle<ObjectTemplate> tmpl = ObjectTemplate::New(isolate);
490 tmpl->SetAccessCheckCallbacks(namedCallback, indexedCallback, data);
491 Handle<Object> instance = tmpl->NewInstance();
492 Handle<Object> global = instance->CreationContext()->Global();
493 global->Set(String::NewFromUtf8(isolate, "obj"), instance);
494 global->Set(kBlockedContextIndex, v8::True(isolate));
495 return instance;
496 }
497
498
499 TEST(NamedAccessCheck) {
500 const AccessType types[] = { ACCESS_GET, ACCESS_HAS };
501 for (size_t i = 0; i < ARRAY_SIZE(types); ++i) {
502 HandleScope scope(CcTest::isolate());
503 LocalContext context(CcTest::isolate());
504 g_access_block_type = types[i];
505 Handle<Object> instance = CreateAccessCheckedObject(
506 CcTest::isolate(),
507 NamedAccessAllowUnlessBlocked,
508 IndexedAccessAlwaysAllowed,
509 String::NewFromUtf8(CcTest::isolate(), "foo"));
510 CompileRun("var records = null;"
511 "var objNoCheck = {};"
512 "var observer = function(r) { records = r };"
513 "Object.observe(obj, observer);"
514 "Object.observe(objNoCheck, observer);");
515 Handle<Value> obj_no_check = CompileRun("objNoCheck");
516 { 404 {
517 LocalContext context2(CcTest::isolate()); 405 Context::Scope mutation_scope(mutation_context);
518 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 406 mutation_context->Global()->Set(
519 instance); 407 String::NewFromUtf8(CcTest::isolate(), "obj"), obj);
520 context2->Global()->Set( 408 CompileRun("obj.foo = 'bar';"
521 String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), 409 "obj.foo = 'baz';"
522 obj_no_check); 410 "delete obj.foo;"
523 CompileRun("var records2 = null;" 411 "Object.defineProperty(obj, 'bar', {value: 'bot'});"
524 "var observer2 = function(r) { records2 = r };" 412 "Array.prototype.push.call(obj, 1, 2, 3);"
525 "Object.observe(obj, observer2);" 413 "Array.prototype.splice.call(obj, 1, 2, 2, 4);"
526 "Object.observe(objNoCheck, observer2);" 414 "Array.prototype.pop.call(obj);"
527 "obj.foo = 'bar';" 415 "Array.prototype.shift.call(obj);");
528 "Object.defineProperty(obj, 'foo', {value: 5});"
529 "Object.defineProperty(obj, 'foo', {get: function(){}});"
530 "obj.bar = 'baz';"
531 "objNoCheck.baz = 'quux'");
532 const RecordExpectation expected_records2[] = {
533 { instance, "add", "foo", Handle<Value>() },
534 { instance, "update", "foo",
535 String::NewFromUtf8(CcTest::isolate(), "bar") },
536 { instance, "reconfigure", "foo",
537 Number::New(CcTest::isolate(), 5) },
538 { instance, "add", "bar", Handle<Value>() },
539 { obj_no_check, "add", "baz", Handle<Value>() },
540 };
541 EXPECT_RECORDS(CompileRun("records2"), expected_records2);
542 } 416 }
543 const RecordExpectation expected_records[] = { 417 }
544 { instance, "add", "bar", Handle<Value>() }, 418 return CompileRun("records ? records.length : 0")->Int32Value();
545 { obj_no_check, "add", "baz", Handle<Value>() } 419 }
546 }; 420
547 EXPECT_RECORDS(CompileRun("records"), expected_records); 421
548 } 422 TEST(ObserverSecurityAAA) {
549 } 423 v8::Isolate* isolate = CcTest::isolate();
550 424 v8::HandleScope scope(isolate);
551 425 v8::Local<Context> contextA = Context::New(isolate);
552 TEST(IndexedAccessCheck) { 426 CHECK_EQ(8, TestObserveSecurity(contextA, contextA, contextA));
553 const AccessType types[] = { ACCESS_GET, ACCESS_HAS }; 427 }
554 for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { 428
555 HandleScope scope(CcTest::isolate()); 429
556 LocalContext context(CcTest::isolate()); 430 TEST(ObserverSecurityA1A2A3) {
557 g_access_block_type = types[i]; 431 v8::Isolate* isolate = CcTest::isolate();
558 Handle<Object> instance = CreateAccessCheckedObject( 432 v8::HandleScope scope(isolate);
559 CcTest::isolate(), NamedAccessAlwaysAllowed, 433
560 IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 7)); 434 v8::Local<Context> contextA1 = Context::New(isolate);
561 CompileRun("var records = null;" 435 v8::Local<Context> contextA2 = Context::New(isolate);
562 "var objNoCheck = {};" 436 v8::Local<Context> contextA3 = Context::New(isolate);
563 "var observer = function(r) { records = r };" 437
564 "Object.observe(obj, observer);" 438 Local<Value> foo = v8_str("foo");
565 "Object.observe(objNoCheck, observer);"); 439 contextA1->SetSecurityToken(foo);
566 Handle<Value> obj_no_check = CompileRun("objNoCheck"); 440 contextA2->SetSecurityToken(foo);
567 { 441 contextA3->SetSecurityToken(foo);
568 LocalContext context2(CcTest::isolate()); 442
569 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 443 CHECK_EQ(8, TestObserveSecurity(contextA1, contextA2, contextA3));
570 instance); 444 }
571 context2->Global()->Set( 445
572 String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), 446
573 obj_no_check); 447 TEST(ObserverSecurityAAB) {
574 CompileRun("var records2 = null;" 448 v8::Isolate* isolate = CcTest::isolate();
575 "var observer2 = function(r) { records2 = r };" 449 v8::HandleScope scope(isolate);
576 "Object.observe(obj, observer2);" 450 v8::Local<Context> contextA = Context::New(isolate);
577 "Object.observe(objNoCheck, observer2);" 451 v8::Local<Context> contextB = Context::New(isolate);
578 "obj[7] = 'foo';" 452 CHECK_EQ(0, TestObserveSecurity(contextA, contextA, contextB));
579 "Object.defineProperty(obj, '7', {value: 5});" 453 }
580 "Object.defineProperty(obj, '7', {get: function(){}});" 454
581 "obj[8] = 'bar';" 455
582 "objNoCheck[42] = 'quux'"); 456 TEST(ObserverSecurityA1A2B) {
583 const RecordExpectation expected_records2[] = { 457 v8::Isolate* isolate = CcTest::isolate();
584 { instance, "add", "7", Handle<Value>() }, 458 v8::HandleScope scope(isolate);
585 { instance, "update", "7", 459
586 String::NewFromUtf8(CcTest::isolate(), "foo") }, 460 v8::Local<Context> contextA1 = Context::New(isolate);
587 { instance, "reconfigure", "7", Number::New(CcTest::isolate(), 5) }, 461 v8::Local<Context> contextA2 = Context::New(isolate);
588 { instance, "add", "8", Handle<Value>() }, 462 v8::Local<Context> contextB = Context::New(isolate);
589 { obj_no_check, "add", "42", Handle<Value>() } 463
590 }; 464 Local<Value> foo = v8_str("foo");
591 EXPECT_RECORDS(CompileRun("records2"), expected_records2); 465 contextA1->SetSecurityToken(foo);
592 } 466 contextA2->SetSecurityToken(foo);
593 const RecordExpectation expected_records[] = { 467
594 { instance, "add", "8", Handle<Value>() }, 468 CHECK_EQ(0, TestObserveSecurity(contextA1, contextA2, contextB));
595 { obj_no_check, "add", "42", Handle<Value>() } 469 }
596 }; 470
597 EXPECT_RECORDS(CompileRun("records"), expected_records); 471
598 } 472 TEST(ObserverSecurityABA) {
599 } 473 v8::Isolate* isolate = CcTest::isolate();
600 474 v8::HandleScope scope(isolate);
601 475 v8::Local<Context> contextA = Context::New(isolate);
602 TEST(SpliceAccessCheck) { 476 v8::Local<Context> contextB = Context::New(isolate);
603 HandleScope scope(CcTest::isolate()); 477 CHECK_EQ(0, TestObserveSecurity(contextA, contextB, contextA));
604 LocalContext context(CcTest::isolate()); 478 }
605 g_access_block_type = ACCESS_GET; 479
606 Handle<Object> instance = CreateAccessCheckedObject( 480
607 CcTest::isolate(), NamedAccessAlwaysAllowed, 481 TEST(ObserverSecurityA1BA2) {
608 IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 1)); 482 v8::Isolate* isolate = CcTest::isolate();
609 CompileRun("var records = null;" 483 v8::HandleScope scope(isolate);
610 "obj[1] = 'foo';" 484 v8::Local<Context> contextA1 = Context::New(isolate);
611 "obj.length = 2;" 485 v8::Local<Context> contextA2 = Context::New(isolate);
612 "var objNoCheck = {1: 'bar', length: 2};" 486 v8::Local<Context> contextB = Context::New(isolate);
613 "observer = function(r) { records = r };" 487
614 "Array.observe(obj, observer);" 488 Local<Value> foo = v8_str("foo");
615 "Array.observe(objNoCheck, observer);"); 489 contextA1->SetSecurityToken(foo);
616 Handle<Value> obj_no_check = CompileRun("objNoCheck"); 490 contextA2->SetSecurityToken(foo);
617 { 491
618 LocalContext context2(CcTest::isolate()); 492 CHECK_EQ(0, TestObserveSecurity(contextA1, contextB, contextA2));
619 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 493 }
620 instance); 494
621 context2->Global()->Set( 495
622 String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check); 496 TEST(ObserverSecurityBAA) {
623 CompileRun("var records2 = null;" 497 v8::Isolate* isolate = CcTest::isolate();
624 "var observer2 = function(r) { records2 = r };" 498 v8::HandleScope scope(isolate);
625 "Array.observe(obj, observer2);" 499 v8::Local<Context> contextA = Context::New(isolate);
626 "Array.observe(objNoCheck, observer2);" 500 v8::Local<Context> contextB = Context::New(isolate);
627 // No one should hear about this: no splice records are emitted 501 CHECK_EQ(0, TestObserveSecurity(contextB, contextA, contextA));
628 // for access-checked objects 502 }
629 "[].push.call(obj, 5);" 503
630 "[].splice.call(obj, 1, 1);" 504
631 "[].pop.call(obj);" 505 TEST(ObserverSecurityBA1A2) {
632 "[].pop.call(objNoCheck);"); 506 v8::Isolate* isolate = CcTest::isolate();
633 // TODO(adamk): Extend EXPECT_RECORDS to be able to assert more things 507 v8::HandleScope scope(isolate);
634 // about splice records. For this test it's not so important since 508 v8::Local<Context> contextA1 = Context::New(isolate);
635 // we just want to guarantee the machinery is in operation at all. 509 v8::Local<Context> contextA2 = Context::New(isolate);
636 const RecordExpectation expected_records2[] = { 510 v8::Local<Context> contextB = Context::New(isolate);
637 { obj_no_check, "splice", "", Handle<Value>() } 511
638 }; 512 Local<Value> foo = v8_str("foo");
639 EXPECT_RECORDS(CompileRun("records2"), expected_records2); 513 contextA1->SetSecurityToken(foo);
640 } 514 contextA2->SetSecurityToken(foo);
641 const RecordExpectation expected_records[] = { 515
642 { obj_no_check, "splice", "", Handle<Value>() } 516 CHECK_EQ(0, TestObserveSecurity(contextB, contextA1, contextA2));
643 }; 517 }
644 EXPECT_RECORDS(CompileRun("records"), expected_records); 518
645 } 519
646 520 TEST(ObserverSecurityNotify) {
647 521 v8::Isolate* isolate = CcTest::isolate();
648 TEST(DisallowAllForAccessKeys) { 522 v8::HandleScope scope(isolate);
649 HandleScope scope(CcTest::isolate()); 523 v8::Local<Context> contextA = Context::New(isolate);
650 LocalContext context(CcTest::isolate()); 524 v8::Local<Context> contextB = Context::New(isolate);
651 Handle<Object> instance = CreateAccessCheckedObject( 525
652 CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed); 526 Context::Scope scopeA(contextA);
653 CompileRun("var records = null;" 527 CompileRun("var obj = {};"
654 "var objNoCheck = {};" 528 "var recordsA = null;"
655 "var observer = function(r) { records = r };" 529 "var observerA = function(r) { recordsA = r };"
656 "Object.observe(obj, observer);" 530 "Object.observe(obj, observerA);");
657 "Object.observe(objNoCheck, observer);"); 531 Handle<Value> obj = CompileRun("obj");
658 Handle<Value> obj_no_check = CompileRun("objNoCheck"); 532
659 { 533 {
660 LocalContext context2(CcTest::isolate()); 534 Context::Scope scopeB(contextB);
661 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), 535 contextB->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"), obj);
662 instance); 536 CompileRun("var recordsB = null;"
663 context2->Global()->Set( 537 "var observerB = function(r) { recordsB = r };"
664 String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check); 538 "Object.observe(obj, observerB);");
665 CompileRun("var records2 = null;" 539 }
666 "var observer2 = function(r) { records2 = r };" 540
667 "Object.observe(obj, observer2);" 541 CompileRun("var notifier = Object.getNotifier(obj);"
668 "Object.observe(objNoCheck, observer2);" 542 "notifier.notify({ type: 'update' });");
669 "obj.foo = 'bar';" 543 CHECK_EQ(1, CompileRun("recordsA ? recordsA.length : 0")->Int32Value());
670 "obj[5] = 'baz';" 544
671 "objNoCheck.baz = 'quux'"); 545 {
672 const RecordExpectation expected_records2[] = { 546 Context::Scope scopeB(contextB);
673 { instance, "add", "foo", Handle<Value>() }, 547 CHECK_EQ(0, CompileRun("recordsB ? recordsB.length : 0")->Int32Value());
674 { instance, "add", "5", Handle<Value>() }, 548 }
675 { obj_no_check, "add", "baz", Handle<Value>() },
676 };
677 EXPECT_RECORDS(CompileRun("records2"), expected_records2);
678 }
679 const RecordExpectation expected_records[] = {
680 { obj_no_check, "add", "baz", Handle<Value>() }
681 };
682 EXPECT_RECORDS(CompileRun("records"), expected_records);
683 }
684
685
686 TEST(AccessCheckDisallowApiModifications) {
687 HandleScope scope(CcTest::isolate());
688 LocalContext context(CcTest::isolate());
689 Handle<Object> instance = CreateAccessCheckedObject(
690 CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
691 CompileRun("var records = null;"
692 "var observer = function(r) { records = r };"
693 "Object.observe(obj, observer);");
694 {
695 LocalContext context2(CcTest::isolate());
696 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
697 instance);
698 CompileRun("var records2 = null;"
699 "var observer2 = function(r) { records2 = r };"
700 "Object.observe(obj, observer2);");
701 instance->Set(5, String::NewFromUtf8(CcTest::isolate(), "bar"));
702 instance->Set(String::NewFromUtf8(CcTest::isolate(), "foo"),
703 String::NewFromUtf8(CcTest::isolate(), "bar"));
704 CompileRun(""); // trigger delivery
705 const RecordExpectation expected_records2[] = {
706 { instance, "add", "5", Handle<Value>() },
707 { instance, "add", "foo", Handle<Value>() }
708 };
709 EXPECT_RECORDS(CompileRun("records2"), expected_records2);
710 }
711 CHECK(CompileRun("records")->IsNull());
712 } 549 }
713 550
714 551
715 TEST(HiddenPropertiesLeakage) { 552 TEST(HiddenPropertiesLeakage) {
716 HandleScope scope(CcTest::isolate()); 553 HandleScope scope(CcTest::isolate());
717 LocalContext context(CcTest::isolate()); 554 LocalContext context(CcTest::isolate());
718 CompileRun("var obj = {};" 555 CompileRun("var obj = {};"
719 "var records = null;" 556 "var records = null;"
720 "var observer = function(r) { records = r };" 557 "var observer = function(r) { records = r };"
721 "Object.observe(obj, observer);"); 558 "Object.observe(obj, observer);");
722 Handle<Value> obj = 559 Handle<Value> obj =
723 context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj")); 560 context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj"));
724 Handle<Object>::Cast(obj) 561 Handle<Object>::Cast(obj)
725 ->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"), 562 ->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"),
726 Null(CcTest::isolate())); 563 Null(CcTest::isolate()));
727 CompileRun(""); // trigger delivery 564 CompileRun(""); // trigger delivery
728 CHECK(CompileRun("records")->IsNull()); 565 CHECK(CompileRun("records")->IsNull());
729 } 566 }
567
568
569 TEST(GetNotifierFromOtherContext) {
570 HandleScope scope(CcTest::isolate());
571 LocalContext context(CcTest::isolate());
572 CompileRun("var obj = {};");
573 Handle<Value> instance = CompileRun("obj");
574 {
575 LocalContext context2(CcTest::isolate());
576 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
577 instance);
578 CHECK(CompileRun("Object.getNotifier(obj)")->IsNull());
579 }
580 }
581
582
583 TEST(GetNotifierFromOtherOrigin) {
584 HandleScope scope(CcTest::isolate());
585 Handle<Value> foo = String::NewFromUtf8(CcTest::isolate(), "foo");
586 Handle<Value> bar = String::NewFromUtf8(CcTest::isolate(), "bar");
587 LocalContext context(CcTest::isolate());
588 context->SetSecurityToken(foo);
589 CompileRun("var obj = {};");
590 Handle<Value> instance = CompileRun("obj");
591 {
592 LocalContext context2(CcTest::isolate());
593 context2->SetSecurityToken(bar);
594 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
595 instance);
596 CHECK(CompileRun("Object.getNotifier(obj)")->IsNull());
597 }
598 }
599
600
601 TEST(GetNotifierFromSameOrigin) {
602 HandleScope scope(CcTest::isolate());
603 Handle<Value> foo = String::NewFromUtf8(CcTest::isolate(), "foo");
604 LocalContext context(CcTest::isolate());
605 context->SetSecurityToken(foo);
606 CompileRun("var obj = {};");
607 Handle<Value> instance = CompileRun("obj");
608 {
609 LocalContext context2(CcTest::isolate());
610 context2->SetSecurityToken(foo);
611 context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
612 instance);
613 CHECK(CompileRun("Object.getNotifier(obj)")->IsObject());
614 }
615 }
OLDNEW
« no previous file with comments | « test/cctest/cctest.status ('k') | test/mjsunit/es7/object-observe.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698