OLD | NEW |
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 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 Handle<Array> recordArray = records.As<Array>(); | 306 Handle<Array> recordArray = records.As<Array>(); |
307 CHECK_EQ(num, static_cast<int>(recordArray->Length())); | 307 CHECK_EQ(num, static_cast<int>(recordArray->Length())); |
308 for (int i = 0; i < num; ++i) { | 308 for (int i = 0; i < num; ++i) { |
309 Handle<Value> record = recordArray->Get(i); | 309 Handle<Value> record = recordArray->Get(i); |
310 CHECK(record->IsObject()); | 310 CHECK(record->IsObject()); |
311 Handle<Object> recordObj = record.As<Object>(); | 311 Handle<Object> recordObj = record.As<Object>(); |
312 CHECK(expectations[i].object->StrictEquals( | 312 CHECK(expectations[i].object->StrictEquals( |
313 recordObj->Get(String::New("object")))); | 313 recordObj->Get(String::New("object")))); |
314 CHECK(String::New(expectations[i].type)->Equals( | 314 CHECK(String::New(expectations[i].type)->Equals( |
315 recordObj->Get(String::New("type")))); | 315 recordObj->Get(String::New("type")))); |
316 CHECK(String::New(expectations[i].name)->Equals( | 316 if (strcmp("splice", expectations[i].type) != 0) { |
317 recordObj->Get(String::New("name")))); | 317 CHECK(String::New(expectations[i].name)->Equals( |
318 if (!expectations[i].old_value.IsEmpty()) { | 318 recordObj->Get(String::New("name")))); |
319 CHECK(expectations[i].old_value->Equals( | 319 if (!expectations[i].old_value.IsEmpty()) { |
320 recordObj->Get(String::New("oldValue")))); | 320 CHECK(expectations[i].old_value->Equals( |
| 321 recordObj->Get(String::New("oldValue")))); |
| 322 } |
321 } | 323 } |
322 } | 324 } |
323 } | 325 } |
324 | 326 |
325 #define EXPECT_RECORDS(records, expectations) \ | 327 #define EXPECT_RECORDS(records, expectations) \ |
326 ExpectRecords(records, expectations, ARRAY_SIZE(expectations)) | 328 ExpectRecords(records, expectations, ARRAY_SIZE(expectations)) |
327 | 329 |
328 TEST(APITestBasicMutation) { | 330 TEST(APITestBasicMutation) { |
329 HarmonyIsolate isolate; | 331 HarmonyIsolate isolate; |
330 HandleScope scope(isolate.GetIsolate()); | 332 HandleScope scope(isolate.GetIsolate()); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 i::Handle<i::JSWeakMap>::cast( | 441 i::Handle<i::JSWeakMap>::cast( |
440 i::GetProperty(observation_state, "notifierObjectInfoMap")); | 442 i::GetProperty(observation_state, "notifierObjectInfoMap")); |
441 CHECK_EQ(1, NumberOfElements(callbackInfoMap)); | 443 CHECK_EQ(1, NumberOfElements(callbackInfoMap)); |
442 CHECK_EQ(1, NumberOfElements(objectInfoMap)); | 444 CHECK_EQ(1, NumberOfElements(objectInfoMap)); |
443 CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap)); | 445 CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap)); |
444 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 446 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
445 CHECK_EQ(0, NumberOfElements(callbackInfoMap)); | 447 CHECK_EQ(0, NumberOfElements(callbackInfoMap)); |
446 CHECK_EQ(0, NumberOfElements(objectInfoMap)); | 448 CHECK_EQ(0, NumberOfElements(objectInfoMap)); |
447 CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap)); | 449 CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap)); |
448 } | 450 } |
| 451 |
| 452 |
| 453 static bool NamedAccessAlwaysAllowed(Local<Object>, Local<Value>, AccessType, |
| 454 Local<Value>) { |
| 455 return true; |
| 456 } |
| 457 |
| 458 |
| 459 static bool IndexedAccessAlwaysAllowed(Local<Object>, uint32_t, AccessType, |
| 460 Local<Value>) { |
| 461 return true; |
| 462 } |
| 463 |
| 464 |
| 465 static AccessType g_access_block_type = ACCESS_GET; |
| 466 |
| 467 |
| 468 static bool NamedAccessAllowUnlessBlocked(Local<Object> host, |
| 469 Local<Value> key, |
| 470 AccessType type, |
| 471 Local<Value>) { |
| 472 if (type != g_access_block_type) return true; |
| 473 Handle<Object> global = Context::GetCurrent()->Global(); |
| 474 Handle<Value> blacklist = global->Get(String::New("blacklist")); |
| 475 if (!blacklist->IsObject()) return true; |
| 476 if (key->IsString()) return !blacklist.As<Object>()->Has(key); |
| 477 return true; |
| 478 } |
| 479 |
| 480 |
| 481 static bool IndexedAccessAllowUnlessBlocked(Local<Object> host, |
| 482 uint32_t index, |
| 483 AccessType type, |
| 484 Local<Value>) { |
| 485 if (type != ACCESS_GET) return true; |
| 486 Handle<Object> global = Context::GetCurrent()->Global(); |
| 487 Handle<Value> blacklist = global->Get(String::New("blacklist")); |
| 488 if (!blacklist->IsObject()) return true; |
| 489 return !blacklist.As<Object>()->Has(index); |
| 490 } |
| 491 |
| 492 |
| 493 static bool BlockAccessKeys(Local<Object> host, Local<Value> key, |
| 494 AccessType type, Local<Value>) { |
| 495 Handle<Object> global = Context::GetCurrent()->Global(); |
| 496 Handle<Value> blacklist = global->Get(String::New("blacklist")); |
| 497 if (!blacklist->IsObject()) return true; |
| 498 return type != ACCESS_KEYS || |
| 499 !blacklist.As<Object>()->Has(String::New("__block_access_keys")); |
| 500 } |
| 501 |
| 502 |
| 503 static Handle<Object> CreateAccessCheckedObject( |
| 504 NamedSecurityCallback namedCallback, |
| 505 IndexedSecurityCallback indexedCallback) { |
| 506 Handle<ObjectTemplate> tmpl = ObjectTemplate::New(); |
| 507 tmpl->SetAccessCheckCallbacks(namedCallback, indexedCallback); |
| 508 Handle<Object> instance = tmpl->NewInstance(); |
| 509 instance->CreationContext()->Global()->Set(String::New("obj"), instance); |
| 510 return instance; |
| 511 } |
| 512 |
| 513 |
| 514 TEST(NamedAccessCheck) { |
| 515 HarmonyIsolate isolate; |
| 516 const AccessType types[] = { ACCESS_GET, ACCESS_HAS }; |
| 517 for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { |
| 518 HandleScope scope(isolate.GetIsolate()); |
| 519 LocalContext context; |
| 520 g_access_block_type = types[i]; |
| 521 Handle<Object> instance = CreateAccessCheckedObject( |
| 522 NamedAccessAllowUnlessBlocked, IndexedAccessAlwaysAllowed); |
| 523 CompileRun("var records = null;" |
| 524 "var objNoCheck = {};" |
| 525 "var blacklist = {foo: true};" |
| 526 "var observer = function(r) { records = r };" |
| 527 "Object.observe(obj, observer);" |
| 528 "Object.observe(objNoCheck, observer);"); |
| 529 Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
| 530 { |
| 531 LocalContext context2; |
| 532 context2->Global()->Set(String::New("obj"), instance); |
| 533 context2->Global()->Set(String::New("objNoCheck"), obj_no_check); |
| 534 CompileRun("var records2 = null;" |
| 535 "var observer2 = function(r) { records2 = r };" |
| 536 "Object.observe(obj, observer2);" |
| 537 "Object.observe(objNoCheck, observer2);" |
| 538 "obj.foo = 'bar';" |
| 539 "Object.defineProperty(obj, 'foo', {value: 5});" |
| 540 "Object.defineProperty(obj, 'foo', {get: function(){}});" |
| 541 "obj.bar = 'baz';" |
| 542 "objNoCheck.baz = 'quux'"); |
| 543 const RecordExpectation expected_records2[] = { |
| 544 { instance, "new", "foo", Handle<Value>() }, |
| 545 { instance, "updated", "foo", String::New("bar") }, |
| 546 { instance, "reconfigured", "foo", Number::New(5) }, |
| 547 { instance, "new", "bar", Handle<Value>() }, |
| 548 { obj_no_check, "new", "baz", Handle<Value>() }, |
| 549 }; |
| 550 EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
| 551 } |
| 552 const RecordExpectation expected_records[] = { |
| 553 { instance, "new", "bar", Handle<Value>() }, |
| 554 { obj_no_check, "new", "baz", Handle<Value>() } |
| 555 }; |
| 556 EXPECT_RECORDS(CompileRun("records"), expected_records); |
| 557 } |
| 558 } |
| 559 |
| 560 |
| 561 TEST(IndexedAccessCheck) { |
| 562 HarmonyIsolate isolate; |
| 563 const AccessType types[] = { ACCESS_GET, ACCESS_HAS }; |
| 564 for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { |
| 565 HandleScope scope(isolate.GetIsolate()); |
| 566 LocalContext context; |
| 567 g_access_block_type = types[i]; |
| 568 Handle<Object> instance = CreateAccessCheckedObject( |
| 569 NamedAccessAlwaysAllowed, IndexedAccessAllowUnlessBlocked); |
| 570 CompileRun("var records = null;" |
| 571 "var objNoCheck = {};" |
| 572 "var blacklist = {7: true};" |
| 573 "var observer = function(r) { records = r };" |
| 574 "Object.observe(obj, observer);" |
| 575 "Object.observe(objNoCheck, observer);"); |
| 576 Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
| 577 { |
| 578 LocalContext context2; |
| 579 context2->Global()->Set(String::New("obj"), instance); |
| 580 context2->Global()->Set(String::New("objNoCheck"), obj_no_check); |
| 581 CompileRun("var records2 = null;" |
| 582 "var observer2 = function(r) { records2 = r };" |
| 583 "Object.observe(obj, observer2);" |
| 584 "Object.observe(objNoCheck, observer2);" |
| 585 "obj[7] = 'foo';" |
| 586 "Object.defineProperty(obj, '7', {value: 5});" |
| 587 "Object.defineProperty(obj, '7', {get: function(){}});" |
| 588 "obj[8] = 'bar';" |
| 589 "objNoCheck[42] = 'quux'"); |
| 590 const RecordExpectation expected_records2[] = { |
| 591 { instance, "new", "7", Handle<Value>() }, |
| 592 { instance, "updated", "7", String::New("foo") }, |
| 593 { instance, "reconfigured", "7", Number::New(5) }, |
| 594 { instance, "new", "8", Handle<Value>() }, |
| 595 { obj_no_check, "new", "42", Handle<Value>() } |
| 596 }; |
| 597 EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
| 598 } |
| 599 const RecordExpectation expected_records[] = { |
| 600 { instance, "new", "8", Handle<Value>() }, |
| 601 { obj_no_check, "new", "42", Handle<Value>() } |
| 602 }; |
| 603 EXPECT_RECORDS(CompileRun("records"), expected_records); |
| 604 } |
| 605 } |
| 606 |
| 607 |
| 608 TEST(SpliceAccessCheck) { |
| 609 HarmonyIsolate isolate; |
| 610 HandleScope scope(isolate.GetIsolate()); |
| 611 LocalContext context; |
| 612 g_access_block_type = ACCESS_GET; |
| 613 Handle<Object> instance = CreateAccessCheckedObject( |
| 614 NamedAccessAlwaysAllowed, IndexedAccessAllowUnlessBlocked); |
| 615 CompileRun("var records = null;" |
| 616 "obj[1] = 'foo';" |
| 617 "obj.length = 2;" |
| 618 "var objNoCheck = {1: 'bar', length: 2};" |
| 619 "var blacklist = {1: true};" |
| 620 "observer = function(r) { records = r };" |
| 621 "Array.observe(obj, observer);" |
| 622 "Array.observe(objNoCheck, observer);"); |
| 623 Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
| 624 { |
| 625 LocalContext context2; |
| 626 context2->Global()->Set(String::New("obj"), instance); |
| 627 context2->Global()->Set(String::New("objNoCheck"), obj_no_check); |
| 628 CompileRun("var records2 = null;" |
| 629 "var observer2 = function(r) { records2 = r };" |
| 630 "Array.observe(obj, observer2);" |
| 631 "Array.observe(objNoCheck, observer2);" |
| 632 // No one should hear about this: no splice records are emitted |
| 633 // for access-checked objects |
| 634 "[].push.call(obj, 5);" |
| 635 "[].splice.call(obj, 1, 1);" |
| 636 "[].pop.call(obj);" |
| 637 "[].pop.call(objNoCheck);"); |
| 638 // TODO(adamk): Extend EXPECT_RECORDS to be able to assert more things |
| 639 // about splice records. For this test it's not so important since |
| 640 // we just want to guarantee the machinery is in operation at all. |
| 641 const RecordExpectation expected_records2[] = { |
| 642 { obj_no_check, "splice", "", Handle<Value>() } |
| 643 }; |
| 644 EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
| 645 } |
| 646 const RecordExpectation expected_records[] = { |
| 647 { obj_no_check, "splice", "", Handle<Value>() } |
| 648 }; |
| 649 EXPECT_RECORDS(CompileRun("records"), expected_records); |
| 650 } |
| 651 |
| 652 |
| 653 TEST(DisallowAllForAccessKeys) { |
| 654 HarmonyIsolate isolate; |
| 655 HandleScope scope(isolate.GetIsolate()); |
| 656 LocalContext context; |
| 657 Handle<Object> instance = CreateAccessCheckedObject( |
| 658 BlockAccessKeys, IndexedAccessAlwaysAllowed); |
| 659 CompileRun("var records = null;" |
| 660 "var objNoCheck = {};" |
| 661 "var observer = function(r) { records = r };" |
| 662 "var blacklist = {__block_access_keys: true};" |
| 663 "Object.observe(obj, observer);" |
| 664 "Object.observe(objNoCheck, observer);"); |
| 665 Handle<Value> obj_no_check = CompileRun("objNoCheck"); |
| 666 { |
| 667 LocalContext context2; |
| 668 context2->Global()->Set(String::New("obj"), instance); |
| 669 context2->Global()->Set(String::New("objNoCheck"), obj_no_check); |
| 670 CompileRun("var records2 = null;" |
| 671 "var observer2 = function(r) { records2 = r };" |
| 672 "Object.observe(obj, observer2);" |
| 673 "Object.observe(objNoCheck, observer2);" |
| 674 "obj.foo = 'bar';" |
| 675 "obj[5] = 'baz';" |
| 676 "objNoCheck.baz = 'quux'"); |
| 677 const RecordExpectation expected_records2[] = { |
| 678 { instance, "new", "foo", Handle<Value>() }, |
| 679 { instance, "new", "5", Handle<Value>() }, |
| 680 { obj_no_check, "new", "baz", Handle<Value>() }, |
| 681 }; |
| 682 EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
| 683 } |
| 684 const RecordExpectation expected_records[] = { |
| 685 { obj_no_check, "new", "baz", Handle<Value>() } |
| 686 }; |
| 687 EXPECT_RECORDS(CompileRun("records"), expected_records); |
| 688 } |
| 689 |
| 690 |
| 691 TEST(AccessCheckDisallowApiModifications) { |
| 692 HarmonyIsolate isolate; |
| 693 HandleScope scope(isolate.GetIsolate()); |
| 694 LocalContext context; |
| 695 Handle<Object> instance = CreateAccessCheckedObject( |
| 696 BlockAccessKeys, IndexedAccessAlwaysAllowed); |
| 697 CompileRun("var records = null;" |
| 698 "var observer = function(r) { records = r };" |
| 699 "var blacklist = {__block_access_keys: true};" |
| 700 "Object.observe(obj, observer);"); |
| 701 { |
| 702 LocalContext context2; |
| 703 context2->Global()->Set(String::New("obj"), instance); |
| 704 CompileRun("var records2 = null;" |
| 705 "var observer2 = function(r) { records2 = r };" |
| 706 "Object.observe(obj, observer2);"); |
| 707 instance->Set(5, String::New("bar")); |
| 708 instance->Set(String::New("foo"), String::New("bar")); |
| 709 CompileRun(""); // trigger delivery |
| 710 const RecordExpectation expected_records2[] = { |
| 711 { instance, "new", "5", Handle<Value>() }, |
| 712 { instance, "new", "foo", Handle<Value>() } |
| 713 }; |
| 714 EXPECT_RECORDS(CompileRun("records2"), expected_records2); |
| 715 } |
| 716 CHECK(CompileRun("records")->IsNull()); |
| 717 } |
OLD | NEW |