Index: test/cctest/test-api-interceptors.cc |
diff --git a/test/cctest/test-api-interceptors.cc b/test/cctest/test-api-interceptors.cc |
index 1e68f944fb09dc6c89aa6a7c424a0525459cbd57..a2acb24d76472796542fd424b0d20b0b3cec17fa 100644 |
--- a/test/cctest/test-api-interceptors.cc |
+++ b/test/cctest/test-api-interceptors.cc |
@@ -2907,3 +2907,204 @@ THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { |
CHECK_EQ(1u, result_array->Length()); |
CHECK(result_array->Get(0)->Equals(v8::Symbol::GetIterator(isolate))); |
} |
+ |
+ |
+namespace { |
+ |
+template <typename T> |
+Local<Object> BuildWrappedObject(v8::Isolate* isolate, T* data) { |
+ auto templ = v8::ObjectTemplate::New(isolate); |
+ templ->SetInternalFieldCount(1); |
+ auto instance = templ->NewInstance(); |
+ instance->SetAlignedPointerInInternalField(0, data); |
+ return instance; |
+} |
+ |
+ |
+template <typename T> |
+T* GetWrappedObject(Local<Value> data) { |
+ return reinterpret_cast<T*>( |
+ Object::Cast(*data)->GetAlignedPointerFromInternalField(0)); |
+} |
+ |
+ |
+struct AccessCheckData { |
+ int count; |
+ bool result; |
+}; |
+ |
+ |
+bool SimpleNamedAccessChecker(Local<v8::Object> global, Local<Value> name, |
+ v8::AccessType type, Local<Value> data) { |
+ auto access_check_data = GetWrappedObject<AccessCheckData>(data); |
+ access_check_data->count++; |
+ return access_check_data->result; |
+} |
+ |
+ |
+bool SimpleIndexedAccessChecker(Local<v8::Object> global, uint32_t index, |
+ v8::AccessType type, Local<Value> data) { |
+ auto access_check_data = GetWrappedObject<AccessCheckData>(data); |
+ access_check_data->count++; |
+ return access_check_data->result; |
+} |
+ |
+ |
+struct ShouldInterceptData { |
+ int value; |
+ bool should_intercept; |
+}; |
+ |
+ |
+void ShouldNamedInterceptor(Local<Name> name, |
+ const v8::PropertyCallbackInfo<Value>& info) { |
+ ApiTestFuzzer::Fuzz(); |
+ CheckReturnValue(info, FUNCTION_ADDR(ShouldNamedInterceptor)); |
+ auto data = GetWrappedObject<ShouldInterceptData>(info.Data()); |
+ if (!data->should_intercept) return; |
+ info.GetReturnValue().Set(v8_num(data->value)); |
+} |
+ |
+ |
+void ShouldIndexedInterceptor(uint32_t, |
+ const v8::PropertyCallbackInfo<Value>& info) { |
+ ApiTestFuzzer::Fuzz(); |
+ CheckReturnValue(info, FUNCTION_ADDR(ShouldIndexedInterceptor)); |
+ auto data = GetWrappedObject<ShouldInterceptData>(info.Data()); |
+ if (!data->should_intercept) return; |
+ info.GetReturnValue().Set(v8_num(data->value)); |
+} |
+ |
+} // namespace |
+ |
+ |
+THREADED_TEST(NamedAllCanReadInterceptor) { |
+ auto isolate = CcTest::isolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ LocalContext context; |
+ |
+ AccessCheckData access_check_data; |
+ access_check_data.result = false; |
+ access_check_data.count = 0; |
+ |
+ ShouldInterceptData intercept_data_0; |
+ intercept_data_0.value = 239; |
+ intercept_data_0.should_intercept = true; |
+ |
+ ShouldInterceptData intercept_data_1; |
+ intercept_data_1.value = 165; |
+ intercept_data_1.should_intercept = false; |
+ |
+ auto intercepted_0 = v8::ObjectTemplate::New(isolate); |
+ { |
+ v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor); |
+ conf.flags = v8::PropertyHandlerFlags::kAllCanRead; |
+ conf.data = |
+ BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0); |
+ intercepted_0->SetHandler(conf); |
+ } |
+ |
+ auto intercepted_1 = v8::ObjectTemplate::New(isolate); |
+ { |
+ v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor); |
+ conf.flags = v8::PropertyHandlerFlags::kAllCanRead; |
+ conf.data = |
+ BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1); |
+ intercepted_1->SetHandler(conf); |
+ } |
+ |
+ auto checked = v8::ObjectTemplate::New(isolate); |
+ checked->SetAccessCheckCallbacks( |
+ SimpleNamedAccessChecker, nullptr, |
+ BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); |
+ |
+ context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); |
+ context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance()); |
+ auto checked_instance = checked->NewInstance(); |
+ checked_instance->Set(v8_str("whatever"), v8_num(17)); |
+ context->Global()->Set(v8_str("checked"), checked_instance); |
+ CompileRun( |
+ "checked.__proto__ = intercepted_1;" |
+ "intercepted_1.__proto__ = intercepted_0;"); |
+ |
+ checked_instance->TurnOnAccessCheck(); |
+ CHECK_EQ(0, access_check_data.count); |
+ |
+ access_check_data.result = true; |
+ ExpectInt32("checked.whatever", 17); |
+ CHECK_EQ(1, access_check_data.count); |
+ |
+ access_check_data.result = false; |
+ ExpectInt32("checked.whatever", intercept_data_0.value); |
+ CHECK_EQ(2, access_check_data.count); |
+ |
+ intercept_data_1.should_intercept = true; |
+ ExpectInt32("checked.whatever", intercept_data_1.value); |
+ CHECK_EQ(3, access_check_data.count); |
+} |
+ |
+ |
+THREADED_TEST(IndexedAllCanReadInterceptor) { |
+ auto isolate = CcTest::isolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ LocalContext context; |
+ |
+ AccessCheckData access_check_data; |
+ access_check_data.result = false; |
+ access_check_data.count = 0; |
+ |
+ ShouldInterceptData intercept_data_0; |
+ intercept_data_0.value = 239; |
+ intercept_data_0.should_intercept = true; |
+ |
+ ShouldInterceptData intercept_data_1; |
+ intercept_data_1.value = 165; |
+ intercept_data_1.should_intercept = false; |
+ |
+ auto intercepted_0 = v8::ObjectTemplate::New(isolate); |
+ { |
+ v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor); |
+ conf.flags = v8::PropertyHandlerFlags::kAllCanRead; |
+ conf.data = |
+ BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_0); |
+ intercepted_0->SetHandler(conf); |
+ } |
+ |
+ auto intercepted_1 = v8::ObjectTemplate::New(isolate); |
+ { |
+ v8::IndexedPropertyHandlerConfiguration conf(ShouldIndexedInterceptor); |
+ conf.flags = v8::PropertyHandlerFlags::kAllCanRead; |
+ conf.data = |
+ BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data_1); |
+ intercepted_1->SetHandler(conf); |
+ } |
+ |
+ auto checked = v8::ObjectTemplate::New(isolate); |
+ checked->SetAccessCheckCallbacks( |
+ nullptr, SimpleIndexedAccessChecker, |
+ BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); |
+ |
+ context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); |
+ context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance()); |
+ auto checked_instance = checked->NewInstance(); |
+ context->Global()->Set(v8_str("checked"), checked_instance); |
+ checked_instance->Set(15, v8_num(17)); |
+ CompileRun( |
+ "checked.__proto__ = intercepted_1;" |
+ "intercepted_1.__proto__ = intercepted_0;"); |
+ |
+ checked_instance->TurnOnAccessCheck(); |
+ CHECK_EQ(0, access_check_data.count); |
+ |
+ access_check_data.result = true; |
+ ExpectInt32("checked[15]", 17); |
+ CHECK_EQ(1, access_check_data.count); |
+ |
+ access_check_data.result = false; |
+ ExpectInt32("checked[15]", intercept_data_0.value); |
+ CHECK_EQ(2, access_check_data.count); |
+ |
+ intercept_data_1.should_intercept = true; |
+ ExpectInt32("checked[15]", intercept_data_1.value); |
+ CHECK_EQ(3, access_check_data.count); |
+} |