Commit db73b059 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

v8binding: Introduce WorldSafeV8Reference class

WorldSafeV8Reference class provides safe access across worlds
plus wrapper-tracing.

The usage is demonstrated at CustomEvent.detail.

Change-Id: I6c640d916063ac87604bd63f25524f8a4f8dd817
Bug: 501866, 755520, 803478
Reviewed-on: https://chromium-review.googlesource.com/c/1358611
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615844}
parent d54516f6
......@@ -9,6 +9,12 @@ import("//third_party/blink/renderer/bindings/modules/v8/v8.gni")
bindings_core_v8_files =
get_path_info([
"core/v8/active_script_wrappable.h",
"core/v8/array_value.cc",
"core/v8/array_value.h",
"core/v8/binding_security.cc",
"core/v8/binding_security.h",
"core/v8/callback_promise_adapter.h",
"core/v8/custom/v8_custom_xpath_ns_resolver.cc",
"core/v8/custom/v8_custom_xpath_ns_resolver.h",
"core/v8/custom/v8_dev_tools_host_custom.cc",
......@@ -26,12 +32,6 @@ bindings_core_v8_files =
"core/v8/custom/v8_shadow_root_custom.cc",
"core/v8/custom/v8_window_custom.cc",
"core/v8/custom/v8_xml_http_request_custom.cc",
"core/v8/active_script_wrappable.h",
"core/v8/array_value.cc",
"core/v8/array_value.h",
"core/v8/binding_security.cc",
"core/v8/binding_security.h",
"core/v8/callback_promise_adapter.h",
"core/v8/custom_wrappable_adapter.cc",
"core/v8/custom_wrappable_adapter.h",
"core/v8/dictionary.cc",
......@@ -39,19 +39,19 @@ bindings_core_v8_files =
"core/v8/dictionary_helper_for_core.cc",
"core/v8/generated_code_helper.cc",
"core/v8/generated_code_helper.h",
"core/v8/initialize_v8_extras_binding.cc",
"core/v8/initialize_v8_extras_binding.h",
"core/v8/idl_dictionary_base.cc",
"core/v8/idl_dictionary_base.h",
"core/v8/idl_types.h",
"core/v8/idl_types_base.h",
"core/v8/initialize_v8_extras_binding.cc",
"core/v8/initialize_v8_extras_binding.h",
"core/v8/iterable.h",
"core/v8/js_based_event_listener.cc",
"core/v8/js_based_event_listener.h",
"core/v8/js_event_handler.cc",
"core/v8/js_event_handler.h",
"core/v8/js_event_handler_for_content_attribute.h",
"core/v8/js_event_handler_for_content_attribute.cc",
"core/v8/js_event_handler_for_content_attribute.h",
"core/v8/js_event_listener.cc",
"core/v8/js_event_listener.h",
"core/v8/local_window_proxy.cc",
......@@ -66,6 +66,7 @@ bindings_core_v8_files =
"core/v8/remote_window_proxy.cc",
"core/v8/remote_window_proxy.h",
"core/v8/retained_object_info.h",
"core/v8/sanitize_script_errors.h",
"core/v8/scheduled_action.cc",
"core/v8/scheduled_action.h",
"core/v8/script_controller.cc",
......@@ -84,7 +85,6 @@ bindings_core_v8_files =
"core/v8/script_iterator.h",
"core/v8/script_module.cc",
"core/v8/script_module.h",
"core/v8/sanitize_script_errors.h",
"core/v8/script_promise.cc",
"core/v8/script_promise.h",
"core/v8/script_promise_property.h",
......@@ -103,6 +103,22 @@ bindings_core_v8_files =
"core/v8/script_streamer_thread.h",
"core/v8/script_value.cc",
"core/v8/script_value.h",
"core/v8/serialization/post_message_helper.cc",
"core/v8/serialization/post_message_helper.h",
"core/v8/serialization/serialization_tag.h",
"core/v8/serialization/serialized_color_params.cc",
"core/v8/serialization/serialized_color_params.h",
"core/v8/serialization/serialized_script_value.cc",
"core/v8/serialization/serialized_script_value.h",
"core/v8/serialization/serialized_script_value_factory.cc",
"core/v8/serialization/serialized_script_value_factory.h",
"core/v8/serialization/transferables.h",
"core/v8/serialization/unpacked_serialized_script_value.cc",
"core/v8/serialization/unpacked_serialized_script_value.h",
"core/v8/serialization/v8_script_value_deserializer.cc",
"core/v8/serialization/v8_script_value_deserializer.h",
"core/v8/serialization/v8_script_value_serializer.cc",
"core/v8/serialization/v8_script_value_serializer.h",
"core/v8/source_location.cc",
"core/v8/source_location.h",
"core/v8/to_v8_for_core.cc",
......@@ -116,6 +132,8 @@ bindings_core_v8_files =
"core/v8/v8_cache_options.h",
"core/v8/v8_code_cache.cc",
"core/v8/v8_code_cache.h",
"core/v8/v8_context_snapshot.cc",
"core/v8/v8_context_snapshot.h",
"core/v8/v8_dom_configuration.cc",
"core/v8/v8_dom_configuration.h",
"core/v8/v8_embedder_graph_builder.cc",
......@@ -134,8 +152,6 @@ bindings_core_v8_files =
"core/v8/v8_initializer.h",
"core/v8/v8_intersection_observer_delegate.cc",
"core/v8/v8_intersection_observer_delegate.h",
"core/v8/v8_throw_dom_exception.cc",
"core/v8/v8_throw_dom_exception.h",
"core/v8/v8_iterator_result_value.cc",
"core/v8/v8_iterator_result_value.h",
"core/v8/v8_object_builder.cc",
......@@ -147,9 +163,9 @@ bindings_core_v8_files =
"core/v8/v8_persistent_value_vector.h",
"core/v8/v8_script_runner.cc",
"core/v8/v8_script_runner.h",
"core/v8/v8_context_snapshot.cc",
"core/v8/v8_context_snapshot.h",
"core/v8/v8_string_resource.h",
"core/v8/v8_throw_dom_exception.cc",
"core/v8/v8_throw_dom_exception.h",
"core/v8/v8_v0_custom_element_lifecycle_callbacks.cc",
"core/v8/v8_v0_custom_element_lifecycle_callbacks.h",
"core/v8/v8_wasm_response_extensions.cc",
......@@ -160,22 +176,8 @@ bindings_core_v8_files =
"core/v8/window_proxy_manager.h",
"core/v8/worker_or_worklet_script_controller.cc",
"core/v8/worker_or_worklet_script_controller.h",
"core/v8/serialization/post_message_helper.cc",
"core/v8/serialization/post_message_helper.h",
"core/v8/serialization/serialized_color_params.cc",
"core/v8/serialization/serialized_color_params.h",
"core/v8/serialization/serialization_tag.h",
"core/v8/serialization/serialized_script_value.cc",
"core/v8/serialization/serialized_script_value.h",
"core/v8/serialization/serialized_script_value_factory.cc",
"core/v8/serialization/serialized_script_value_factory.h",
"core/v8/serialization/transferables.h",
"core/v8/serialization/unpacked_serialized_script_value.cc",
"core/v8/serialization/unpacked_serialized_script_value.h",
"core/v8/serialization/v8_script_value_deserializer.cc",
"core/v8/serialization/v8_script_value_deserializer.h",
"core/v8/serialization/v8_script_value_serializer.cc",
"core/v8/serialization/v8_script_value_serializer.h",
"core/v8/world_safe_v8_reference.cc",
"core/v8/world_safe_v8_reference.h",
],
"abspath")
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
// static
v8::Local<v8::Value> WorldSafeV8ReferenceInternal::ToWorldSafeValue(
ScriptState* target_script_state,
const TraceWrapperV8Reference<v8::Value>& v8_reference,
const DOMWrapperWorld& v8_reference_world) {
DCHECK(!v8_reference.IsEmpty());
v8::Isolate* isolate = target_script_state->GetIsolate();
if (&v8_reference_world == &target_script_state->World())
return v8_reference.NewLocal(isolate);
// If |v8_reference| is a v8::Object, clones |v8_reference| in the context of
// |target_script_state| and returns it. Otherwise returns |v8_reference|
// itself that is already safe to access in |target_script_state|.
v8::Local<v8::Value> value = v8_reference.NewLocal(isolate);
if (!value->IsObject())
return value;
v8::Context::Scope target_context_scope(target_script_state->GetContext());
return SerializedScriptValue::SerializeAndSwallowExceptions(isolate, value)
->Deserialize(isolate);
}
// static
void WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(
const DOMWrapperWorld& world,
v8::Local<v8::Value> value) {
if (!value->IsObject())
return;
ScriptState* script_state =
ScriptState::From(value.As<v8::Object>()->CreationContext());
CHECK_EQ(&world, &script_state->World());
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "v8/include/v8.h"
namespace blink {
class ScriptState;
// This is a namespace to provide utility functions to WorldSafeV8Reference.
class WorldSafeV8ReferenceInternal final {
STATIC_ONLY(WorldSafeV8ReferenceInternal);
private:
// Returns a V8 reference that is safe to access in |target_script_state|.
// The return value may be a cloned object.
//
// TODO(crbug.com/803478): ScriptValue::V8ValueFor should be replaced with
// this function, or these two functions should be merged at least.
static v8::Local<v8::Value> ToWorldSafeValue(
ScriptState* target_script_state,
const TraceWrapperV8Reference<v8::Value>& v8_reference,
const DOMWrapperWorld& v8_reference_world);
// Checks the world of |value|'s creation context if |value| is a v8::Object.
// The given |world| and |value|'s world must match. Otherwise, crashes.
//
// TODO(yukishiino): Find the best place to put this function. We might want
// to share this function among other clients, e.g. access to wrapper objects
// across worlds.
static void MaybeCheckCreationContextWorld(const DOMWrapperWorld& world,
v8::Local<v8::Value> value);
template <typename V8Type>
friend class WorldSafeV8Reference;
};
// This class provides safe access to v8::Value across worlds. This class
// provides accessors that check whether the value is accessed in the same world
// or not, also provides an accessor that clones the value when accessed across
// worlds.
template <typename V8Type>
class WorldSafeV8Reference final {
DISALLOW_NEW();
public:
WorldSafeV8Reference() = default;
explicit WorldSafeV8Reference(v8::Isolate* isolate, v8::Local<V8Type> value)
: v8_reference_(isolate, value),
world_(&DOMWrapperWorld::Current(isolate)) {
MaybeCheckCreationContextWorld(*world_.get(), value);
}
~WorldSafeV8Reference() = default;
// Returns the V8 reference. Crashes if |target_script_state|'s world is
// different from this V8 reference's world.
v8::Local<V8Type> Get(ScriptState* target_script_state) const {
DCHECK(!v8_reference_.IsEmpty());
CHECK_EQ(world_.get(), &target_script_state->World());
return v8_reference_.NewLocal(target_script_state->GetIsolate());
}
// Returns a V8 reference that is safe to access in |target_script_state|.
// The return value may be a cloned object.
v8::Local<V8Type> GetAcrossWorld(ScriptState* target_script_state) const {
return WorldSafeV8ReferenceInternal::ToWorldSafeValue(
target_script_state, v8_reference_, *world_.get())
.template As<V8Type>();
}
// Sets a new V8 reference. Crashes if |new_value|'s world is different from
// this V8 reference's world.
void Set(v8::Isolate* isolate, v8::Local<V8Type> new_value) {
DCHECK(!new_value.IsEmpty());
const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate);
MaybeCheckCreationContextWorld(new_world, new_value);
CHECK(v8_reference_.IsEmpty() || world_.get() == &new_world);
v8_reference_.Set(isolate, new_value);
world_ = WrapRefCounted(&new_world);
}
// Forcibly sets a new V8 reference even when the worlds are different. The
// world of this V8 reference will be |new_value|'s world.
void SetAcrossWorld(v8::Isolate* isolate, v8::Local<V8Type> new_value) {
DCHECK(!new_value.IsEmpty());
const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate);
v8_reference_.Set(isolate, new_value);
world_ = WrapRefCounted(&new_world);
}
void Reset() {
v8_reference_.Clear();
world_.reset();
}
bool IsEmpty() const { return v8_reference_.IsEmpty(); }
void Trace(blink::Visitor* visitor) { visitor->Trace(v8_reference_); }
private:
TraceWrapperV8Reference<V8Type> v8_reference_;
// The world of the current context at the time when |v8_reference_| was set.
// It's guaranteed that, if |v8_reference_| is a v8::Object, the world of the
// creation context of |v8_reference_| is the same as |world_|.
scoped_refptr<const DOMWrapperWorld> world_;
DISALLOW_COPY_AND_ASSIGN(WorldSafeV8Reference);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_
......@@ -25,8 +25,6 @@
#include "third_party/blink/renderer/core/dom/events/custom_event.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h"
#include "third_party/blink/renderer/core/event_interface_names.h"
namespace blink {
......@@ -37,10 +35,9 @@ CustomEvent::CustomEvent(ScriptState* script_state,
const AtomicString& type,
const CustomEventInit* initializer)
: Event(type, initializer) {
world_ = WrapRefCounted(&script_state->World());
if (initializer->hasDetail()) {
detail_.Set(initializer->detail().GetIsolate(),
initializer->detail().V8Value());
detail_.SetAcrossWorld(initializer->detail().GetIsolate(),
initializer->detail().V8Value());
}
}
......@@ -52,23 +49,15 @@ void CustomEvent::initCustomEvent(ScriptState* script_state,
bool cancelable,
const ScriptValue& script_value) {
initEvent(type, bubbles, cancelable);
world_ = WrapRefCounted(&script_state->World());
if (!IsBeingDispatched() && !script_value.IsEmpty())
detail_.Set(script_value.GetIsolate(), script_value.V8Value());
detail_.SetAcrossWorld(script_value.GetIsolate(), script_value.V8Value());
}
ScriptValue CustomEvent::detail(ScriptState* script_state) const {
v8::Isolate* isolate = script_state->GetIsolate();
if (detail_.IsEmpty())
return ScriptValue(script_state, v8::Null(isolate));
// Returns a clone of |detail_| if the world is different.
if (!world_ || world_->GetWorldId() != script_state->World().GetWorldId()) {
v8::Local<v8::Value> value = detail_.NewLocal(isolate);
scoped_refptr<SerializedScriptValue> serialized =
SerializedScriptValue::SerializeAndSwallowExceptions(isolate, value);
return ScriptValue(script_state, serialized->Deserialize(isolate));
}
return ScriptValue(script_state, detail_.NewLocal(isolate));
return ScriptValue(script_state, detail_.GetAcrossWorld(script_state));
}
const AtomicString& CustomEvent::InterfaceName() const {
......
......@@ -26,11 +26,10 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_CUSTOM_EVENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_EVENTS_CUSTOM_EVENT_H_
#include "third_party/blink/renderer/bindings/core/v8/world_safe_v8_reference.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/custom_event_init.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
namespace blink {
......@@ -66,8 +65,7 @@ class CORE_EXPORT CustomEvent final : public Event {
void Trace(blink::Visitor*) override;
private:
scoped_refptr<DOMWrapperWorld> world_;
TraceWrapperV8Reference<v8::Value> detail_;
WorldSafeV8Reference<v8::Value> detail_;
};
} // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment