diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-24 11:40:17 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-24 12:42:11 +0000 |
commit | 5d87695f37678f96492b258bbab36486c59866b4 (patch) | |
tree | be9783bbaf04fb930c4d74ca9c00b5e7954c8bc6 /chromium/mojo | |
parent | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (diff) | |
download | qtwebengine-chromium-5d87695f37678f96492b258bbab36486c59866b4.tar.gz |
BASELINE: Update Chromium to 75.0.3770.56
Change-Id: I86d2007fd27a45d5797eee06f4c9369b8b50ac4f
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/mojo')
111 files changed, 2377 insertions, 1071 deletions
diff --git a/chromium/mojo/core/BUILD.gn b/chromium/mojo/core/BUILD.gn index acfbeb9e508..515972a9cf5 100644 --- a/chromium/mojo/core/BUILD.gn +++ b/chromium/mojo/core/BUILD.gn @@ -6,6 +6,10 @@ import("//build/config/nacl/config.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/test.gni") +if (is_mac) { + import("//third_party/protobuf/proto_library.gni") +} + component("embedder_internal") { output_name = "mojo_core_embedder_internal" public_deps = [ @@ -126,6 +130,7 @@ template("core_impl_source_set") { if (is_mac && !is_ios) { sources += [ + "channel_mac.cc", "mach_port_relay.cc", "mach_port_relay.h", ] @@ -347,6 +352,57 @@ fuzzer_test("mojo_core_channel_fuzzer") { ] } +if (is_mac) { + protoc_convert("mojo_core_channel_mac_fuzzer_convert_corpus") { + sources = [ + "test/data/channel_mac/bad_handshake1.textproto", + "test/data/channel_mac/bad_handshake2.textproto", + "test/data/channel_mac/bad_handshake3.textproto", + "test/data/channel_mac/bad_message1.textproto", + "test/data/channel_mac/complex_messages.textproto", + "test/data/channel_mac/double_handshake.textproto", + "test/data/channel_mac/handshake.textproto", + "test/data/channel_mac/invalid_handles.textproto", + "test/data/channel_mac/non_complex_with_descriptor_count.textproto", + "test/data/channel_mac/ool_type_mismatch.textproto", + "test/data/channel_mac/simple_message1.textproto", + "test/data/channel_mac/simple_message2.textproto", + ] + + inputs = [ + "test/data/channel_mac/channel_mac.proto", + "//testing/libfuzzer/fuzzers/mach/mach_message.proto", + ] + + output_pattern = "$target_gen_dir/mojo_core_channel_mac_corpus/{{source_name_part}}.binarypb" + + args = [ + "--encode=mojo_fuzzer.ChannelMac", + "-I", + rebase_path("//testing/libfuzzer/fuzzers/mach"), + "-I", + rebase_path("//mojo/core/test/data/channel_mac"), + "channel_mac.proto", + ] + } + + fuzzer_test("mojo_core_channel_mac_fuzzer") { + sources = [ + "channel_mac_fuzzer.cc", + ] + seed_corpus = "$target_gen_dir/mojo_core_channel_mac_corpus" + seed_corpus_deps = [ ":mojo_core_channel_mac_fuzzer_convert_corpus" ] + deps = [ + ":core_impl_for_fuzzers", + "test:channel_mac_proto", + "//base", + "//base/test:test_support", + "//testing/libfuzzer/fuzzers/mach:converter", + "//third_party/libprotobuf-mutator", + ] + } +} + fuzzer_test("mojo_core_node_channel_fuzzer") { sources = [ "node_channel_fuzzer.cc", diff --git a/chromium/mojo/core/channel.cc b/chromium/mojo/core/channel.cc index c641e66f0c9..7daaaa13d22 100644 --- a/chromium/mojo/core/channel.cc +++ b/chromium/mojo/core/channel.cc @@ -19,6 +19,7 @@ #include "build/build_config.h" #include "mojo/core/configuration.h" #include "mojo/core/core.h" +#include "mojo/public/cpp/platform/features.h" #if defined(OS_MACOSX) && !defined(OS_IOS) #include "base/mac/mach_logging.h" @@ -153,8 +154,12 @@ Channel::Message::Message(size_t capacity, mach_ports_header_->num_ports = 0; // Initialize all handles to invalid values. for (size_t i = 0; i < max_handles_; ++i) { - mach_ports_header_->entries[i] = {0, - static_cast<uint32_t>(MACH_PORT_NULL)}; + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + mach_ports_header_->entries[i].mach_entry.type = {0}; + } else { + mach_ports_header_->entries[i].posix_entry = { + 0, static_cast<uint32_t>(MACH_PORT_NULL)}; + } } #endif } @@ -440,36 +445,51 @@ void Channel::Message::SetHandles( #if defined(OS_MACOSX) && !defined(OS_IOS) size_t mach_port_index = 0; + const bool use_channel_mac = + base::FeatureList::IsEnabled(features::kMojoChannelMac); if (mach_ports_header_) { for (size_t i = 0; i < max_handles_; ++i) { - mach_ports_header_->entries[i] = {0, - static_cast<uint32_t>(MACH_PORT_NULL)}; + if (use_channel_mac) { + mach_ports_header_->entries[i].mach_entry.type = {0}; + } else { + mach_ports_header_->entries[i].posix_entry = { + 0, static_cast<uint32_t>(MACH_PORT_NULL)}; + } } for (size_t i = 0; i < handle_vector_.size(); i++) { - if (!handle_vector_[i].is_mach_port_name() && - !handle_vector_[i].handle().is_mach_port()) { - DCHECK(handle_vector_[i].handle().is_valid_fd()); - continue; + if (use_channel_mac) { + mach_ports_header_->entries[i].mach_entry.type = + static_cast<uint8_t>(handle_vector_[i].handle().type()); + } else { + if (!handle_vector_[i].is_mach_port_name() && + !handle_vector_[i].handle().is_mach_port()) { + DCHECK(handle_vector_[i].handle().is_valid_fd()); + continue; + } + + mach_port_t port = handle_vector_[i].is_mach_port_name() + ? handle_vector_[i].mach_port_name() + : handle_vector_[i].handle().GetMachPort().get(); + mach_ports_header_->entries[mach_port_index].posix_entry.index = i; + mach_ports_header_->entries[mach_port_index].posix_entry.mach_port = + port; + mach_port_index++; } - - mach_port_t port = handle_vector_[i].is_mach_port_name() - ? handle_vector_[i].mach_port_name() - : handle_vector_[i].handle().GetMachPort().get(); - mach_ports_header_->entries[mach_port_index].index = i; - mach_ports_header_->entries[mach_port_index].mach_port = port; - mach_port_index++; } - mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index); + mach_ports_header_->num_ports = + use_channel_mac ? handle_vector_.size() + : static_cast<uint16_t>(mach_port_index); } #endif } std::vector<PlatformHandleInTransit> Channel::Message::TakeHandles() { #if defined(OS_MACOSX) && !defined(OS_IOS) - if (mach_ports_header_) { + if (mach_ports_header_ && + !base::FeatureList::IsEnabled(features::kMojoChannelMac)) { for (size_t i = 0; i < max_handles_; ++i) { - mach_ports_header_->entries[i] = {0, - static_cast<uint32_t>(MACH_PORT_NULL)}; + mach_ports_header_->entries[i].posix_entry = { + 0, static_cast<uint32_t>(MACH_PORT_NULL)}; } mach_ports_header_->num_ports = 0; } @@ -484,18 +504,22 @@ Channel::Message::TakeHandlesForTransport() { NOTREACHED(); return std::vector<PlatformHandleInTransit>(); #elif defined(OS_MACOSX) && !defined(OS_IOS) - std::vector<PlatformHandleInTransit> non_mach_handles; - for (auto& handle : handle_vector_) { - if (handle.is_mach_port_name() || handle.handle().is_mach_port()) { - // Ownership is effectively transferred to the receiving process - // out-of-band via MachPortRelay. - handle.CompleteTransit(); - } else { - non_mach_handles.emplace_back(std::move(handle)); + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + return std::move(handle_vector_); + } else { + std::vector<PlatformHandleInTransit> non_mach_handles; + for (auto& handle : handle_vector_) { + if (handle.is_mach_port_name() || handle.handle().is_mach_port()) { + // Ownership is effectively transferred to the receiving process + // out-of-band via MachPortRelay. + handle.CompleteTransit(); + } else { + non_mach_handles.emplace_back(std::move(handle)); + } } + handle_vector_.clear(); + return non_mach_handles; } - handle_vector_.clear(); - return non_mach_handles; #else return std::move(handle_vector_); #endif @@ -622,10 +646,14 @@ class Channel::ReadBuffer { DISALLOW_COPY_AND_ASSIGN(ReadBuffer); }; -Channel::Channel(Delegate* delegate, HandlePolicy handle_policy) +Channel::Channel(Delegate* delegate, + HandlePolicy handle_policy, + DispatchBufferPolicy buffer_policy) : delegate_(delegate), handle_policy_(handle_policy), - read_buffer_(new ReadBuffer) {} + read_buffer_(buffer_policy == DispatchBufferPolicy::kManaged + ? new ReadBuffer + : nullptr) {} Channel::~Channel() {} @@ -645,7 +673,8 @@ char* Channel::GetReadBuffer(size_t* buffer_capacity) { } bool Channel::OnReadComplete(size_t bytes_read, size_t* next_read_size_hint) { - bool did_consume_message = false; + DCHECK(read_buffer_); + *next_read_size_hint = kReadBufferSize; read_buffer_->Claim(bytes_read); while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) { // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could @@ -656,98 +685,115 @@ bool Channel::OnReadComplete(size_t bytes_read, size_t* next_read_size_hint) { read_buffer_->Realign(); } - // We have at least enough data available for a LegacyHeader. - const Message::LegacyHeader* legacy_header = - reinterpret_cast<const Message::LegacyHeader*>( - read_buffer_->occupied_bytes()); - - const size_t kMaxMessageSize = GetConfiguration().max_message_num_bytes; - if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) || - legacy_header->num_bytes > kMaxMessageSize) { - LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes; + DispatchResult result = + TryDispatchMessage(base::make_span(read_buffer_->occupied_bytes(), + read_buffer_->num_occupied_bytes()), + next_read_size_hint); + if (result == DispatchResult::kOK) { + read_buffer_->Discard(*next_read_size_hint); + *next_read_size_hint = 0; + } else if (result == DispatchResult::kNotEnoughData) { + return true; + } else if (result == DispatchResult::kMissingHandles) { + break; + } else if (result == DispatchResult::kError) { return false; } + } + return true; +} - if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) { - // Not enough data available to read the full message. Hint to the - // implementation that it should try reading the full size of the message. - *next_read_size_hint = - legacy_header->num_bytes - read_buffer_->num_occupied_bytes(); - return true; - } +Channel::DispatchResult Channel::TryDispatchMessage( + base::span<const char> buffer, + size_t* size_hint) { + bool did_consume_message = false; - const Message::Header* header = nullptr; - if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) { - header = reinterpret_cast<const Message::Header*>(legacy_header); - } + // We have at least enough data available for a LegacyHeader. + const Message::LegacyHeader* legacy_header = + reinterpret_cast<const Message::LegacyHeader*>(buffer.data()); - size_t extra_header_size = 0; - const void* extra_header = nullptr; - size_t payload_size = 0; - void* payload = nullptr; - if (header) { - if (header->num_header_bytes < sizeof(Message::Header) || - header->num_header_bytes > header->num_bytes) { - LOG(ERROR) << "Invalid message header size: " - << header->num_header_bytes; - return false; - } - extra_header_size = header->num_header_bytes - sizeof(Message::Header); - extra_header = extra_header_size ? header + 1 : nullptr; - payload_size = header->num_bytes - header->num_header_bytes; - payload = payload_size - ? reinterpret_cast<Message::Header*>( - const_cast<char*>(read_buffer_->occupied_bytes()) + - header->num_header_bytes) - : nullptr; - } else { - payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader); - payload = payload_size - ? const_cast<Message::LegacyHeader*>(&legacy_header[1]) - : nullptr; - } + const size_t kMaxMessageSize = GetConfiguration().max_message_num_bytes; + if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) || + legacy_header->num_bytes > kMaxMessageSize) { + LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes; + return DispatchResult::kError; + } - const uint16_t num_handles = - header ? header->num_handles : legacy_header->num_handles; - std::vector<PlatformHandle> handles; - bool deferred = false; - if (num_handles > 0) { - if (handle_policy_ == HandlePolicy::kRejectHandles) - return false; - - if (!GetReadPlatformHandles(payload, payload_size, num_handles, - extra_header, extra_header_size, &handles, - &deferred)) { - return false; - } + if (buffer.size() < legacy_header->num_bytes) { + // Not enough data available to read the full message. Hint to the + // implementation that it should try reading the full size of the message. + *size_hint = legacy_header->num_bytes - buffer.size(); + return DispatchResult::kNotEnoughData; + } - if (handles.empty()) { - // Not enough handles available for this message. - break; - } + const Message::Header* header = nullptr; + if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) { + header = reinterpret_cast<const Message::Header*>(legacy_header); + } + + size_t extra_header_size = 0; + const void* extra_header = nullptr; + size_t payload_size = 0; + void* payload = nullptr; + if (header) { + if (header->num_header_bytes < sizeof(Message::Header) || + header->num_header_bytes > header->num_bytes) { + LOG(ERROR) << "Invalid message header size: " << header->num_header_bytes; + return DispatchResult::kError; } + extra_header_size = header->num_header_bytes - sizeof(Message::Header); + extra_header = extra_header_size ? header + 1 : nullptr; + payload_size = header->num_bytes - header->num_header_bytes; + payload = + payload_size + ? reinterpret_cast<Message::Header*>( + const_cast<char*>(buffer.data()) + header->num_header_bytes) + : nullptr; + } else { + payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader); + payload = payload_size + ? const_cast<Message::LegacyHeader*>(&legacy_header[1]) + : nullptr; + } - // We've got a complete message! Dispatch it and try another. - if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY && - legacy_header->message_type != Message::MessageType::NORMAL) { - DCHECK(!deferred); - if (!OnControlMessage(legacy_header->message_type, payload, payload_size, - std::move(handles))) { - return false; - } - did_consume_message = true; - } else if (deferred) { - did_consume_message = true; - } else if (delegate_) { - delegate_->OnChannelMessage(payload, payload_size, std::move(handles)); - did_consume_message = true; + const uint16_t num_handles = + header ? header->num_handles : legacy_header->num_handles; + std::vector<PlatformHandle> handles; + bool deferred = false; + if (num_handles > 0) { + if (handle_policy_ == HandlePolicy::kRejectHandles) + return DispatchResult::kError; + + if (!GetReadPlatformHandles(payload, payload_size, num_handles, + extra_header, extra_header_size, &handles, + &deferred)) { + return DispatchResult::kError; } - read_buffer_->Discard(legacy_header->num_bytes); + if (handles.empty()) { + // Not enough handles available for this message. + return DispatchResult::kMissingHandles; + } } - *next_read_size_hint = did_consume_message ? 0 : kReadBufferSize; - return true; + // We've got a complete message! Dispatch it and try another. + if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY && + legacy_header->message_type != Message::MessageType::NORMAL) { + DCHECK(!deferred); + if (!OnControlMessage(legacy_header->message_type, payload, payload_size, + std::move(handles))) { + return DispatchResult::kError; + } + did_consume_message = true; + } else if (deferred) { + did_consume_message = true; + } else if (delegate_) { + delegate_->OnChannelMessage(payload, payload_size, std::move(handles)); + did_consume_message = true; + } + + *size_hint = legacy_header->num_bytes; + return DispatchResult::kOK; } void Channel::OnError(Error error) { diff --git a/chromium/mojo/core/channel.h b/chromium/mojo/core/channel.h index 9d0f8fd05ae..e06ce1af2b9 100644 --- a/chromium/mojo/core/channel.h +++ b/chromium/mojo/core/channel.h @@ -42,6 +42,17 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // platform handle attachments and treat them as malformed messages. kRejectHandles, }; + enum class DispatchBufferPolicy { + // If the Channel is constructed in this mode, it will create and manage a + // buffer that implementations should manipulate with GetReadBuffer() and + // OnReadComplete(). + kManaged, + + // If the Channel is constructed in this mode, it will not create and + // manage a buffer for the implementation. Instead, the implementation must + // use its own buffer and pass spans of it to TryDispatchMessage(). + kUnmanaged, + }; struct Message; @@ -100,12 +111,22 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel }; #if defined(OS_MACOSX) && !defined(OS_IOS) - struct MachPortsEntry { - // Index of Mach port in the original vector of PlatformHandleInTransits. - uint16_t index; - - // Mach port name. - uint32_t mach_port; + union MachPortsEntry { + // Used with ChannelPosix. + struct { + // Index of Mach port in the original vector of + // PlatformHandleInTransits. + uint16_t index; + + // Mach port name. + uint32_t mach_port; + } posix_entry; + + // Used with ChannelMac. + struct { + // The PlatformHandle::Type. + uint8_t type; + } mach_entry; static_assert(sizeof(mach_port_t) <= sizeof(uint32_t), "mach_port_t must be no larger than uint32_t"); }; @@ -312,7 +333,12 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel virtual void LeakHandle() = 0; protected: - Channel(Delegate* delegate, HandlePolicy handle_policy); + // Constructor for implementations to call. |delegate| and |handle_policy| + // should be passed from Create(). |buffer_policy| should be specified by + // the implementation. + Channel(Delegate* delegate, + HandlePolicy handle_policy, + DispatchBufferPolicy buffer_policy = DispatchBufferPolicy::kManaged); virtual ~Channel(); Delegate* delegate() const { return delegate_; } @@ -323,14 +349,38 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // // Returns the address of a buffer which can be written to, and indicates its // actual capacity in |*buffer_capacity|. + // + // This should only be used with DispatchBufferPolicy::kManaged. char* GetReadBuffer(size_t* buffer_capacity); // Called by the implementation when new data is available in the read // buffer. Returns false to indicate an error. Upon success, // |*next_read_size_hint| will be set to a recommended size for the next - // read done by the implementation. + // read done by the implementation. This should only be used with + // DispatchBufferPolicy::kManaged. bool OnReadComplete(size_t bytes_read, size_t* next_read_size_hint); + // Called by the implementation to deserialize a message stored in |buffer|. + // If the channel was created with DispatchBufferPolicy::kUnmanaged, the + // implementation should call this directly. If it was created with kManaged, + // OnReadComplete() will call this. |*size_hint| will be set to a recommended + // size for the next read done by the implementation. + enum class DispatchResult { + // The message was dispatched and consumed. |size_hint| contains the size + // of the message. + kOK, + // The message could not be deserialized because |buffer| does not contain + // enough data. |size_hint| contains the amount of data missing. + kNotEnoughData, + // The message has associated handles that were not transferred in this + // message. + kMissingHandles, + // An error occurred during processing. + kError, + }; + DispatchResult TryDispatchMessage(base::span<const char> buffer, + size_t* size_hint); + // Called by the implementation when something goes horribly wrong. It is NOT // OK to call this synchronously from any public interface methods. void OnError(Error error); diff --git a/chromium/mojo/core/channel_fuchsia.cc b/chromium/mojo/core/channel_fuchsia.cc index eb30cb9fef9..e603731744d 100644 --- a/chromium/mojo/core/channel_fuchsia.cc +++ b/chromium/mojo/core/channel_fuchsia.cc @@ -300,8 +300,8 @@ class ChannelFuchsia : public Channel, zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {}; zx_status_t read_result = - handle_.read(0, buffer, buffer_capacity, &bytes_read, handles, - base::size(handles), &handles_read); + handle_.rea2(0, buffer, handles, buffer_capacity, base::size(handles), + &bytes_read, &handles_read); if (read_result == ZX_OK) { for (size_t i = 0; i < handles_read; ++i) { incoming_handles_.emplace_back(handles[i]); diff --git a/chromium/mojo/core/channel_mac.cc b/chromium/mojo/core/channel_mac.cc new file mode 100644 index 00000000000..8820afe0a0c --- /dev/null +++ b/chromium/mojo/core/channel_mac.cc @@ -0,0 +1,718 @@ +// Copyright 2019 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 "mojo/core/channel.h" + +#include <mach/mach.h> +#include <string.h> +#include <unistd.h> + +#include <algorithm> +#include <memory> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/containers/buffer_iterator.h" +#include "base/containers/circular_deque.h" +#include "base/containers/span.h" +#include "base/logging.h" +#include "base/mac/mach_logging.h" +#include "base/mac/scoped_mach_msg_destroy.h" +#include "base/mac/scoped_mach_port.h" +#include "base/mac/scoped_mach_vm.h" +#include "base/message_loop/message_loop_current.h" +#include "base/message_loop/message_pump_for_io.h" +#include "base/strings/stringprintf.h" + +extern "C" { +kern_return_t fileport_makeport(int fd, mach_port_t*); +int fileport_makefd(mach_port_t); +} // extern "C" + +namespace mojo { +namespace core { + +namespace { + +constexpr mach_msg_id_t kChannelMacHandshakeMsgId = 'mjhs'; +constexpr mach_msg_id_t kChannelMacInlineMsgId = 'MOJO'; +constexpr mach_msg_id_t kChannelMacOOLMsgId = 'MOJ+'; + +class ChannelMac : public Channel, + public base::MessageLoopCurrent::DestructionObserver, + public base::MessagePumpKqueue::MachPortWatcher { + public: + ChannelMac(Delegate* delegate, + ConnectionParams connection_params, + HandlePolicy handle_policy, + scoped_refptr<base::TaskRunner> io_task_runner) + : Channel(delegate, handle_policy, DispatchBufferPolicy::kUnmanaged), + self_(this), + io_task_runner_(io_task_runner), + watch_controller_(FROM_HERE) { + PlatformHandle channel_handle; + if (connection_params.server_endpoint().is_valid()) { + channel_handle = + connection_params.TakeServerEndpoint().TakePlatformHandle(); + } else { + channel_handle = connection_params.TakeEndpoint().TakePlatformHandle(); + } + + if (channel_handle.is_mach_send()) { + send_port_ = channel_handle.TakeMachSendRight(); + } else if (channel_handle.is_mach_receive()) { + receive_port_ = channel_handle.TakeMachReceiveRight(); + } else { + NOTREACHED(); + } + } + + void Start() override { + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChannelMac::StartOnIOThread, this)); + } + + void ShutDownImpl() override { + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChannelMac::ShutDownOnIOThread, this)); + } + + void Write(MessagePtr message) override { + base::AutoLock lock(write_lock_); + + if (reject_writes_) { + return; + } + + // If the channel is not fully established, queue pending messages. + if (!handshake_done_) { + pending_messages_.push_back(std::move(message)); + return; + } + + // If messages are being queued, enqueue |message| and try to flush + // the queue. + if (send_buffer_contains_message_ || !pending_messages_.empty()) { + pending_messages_.push_back(std::move(message)); + SendPendingMessagesLocked(); + return; + } + + SendMessageLocked(std::move(message)); + } + + void LeakHandle() override { + DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); + leak_handles_ = true; + } + + bool GetReadPlatformHandles(const void* payload, + size_t payload_size, + size_t num_handles, + const void* extra_header, + size_t extra_header_size, + std::vector<PlatformHandle>* handles, + bool* deferred) override { + // Validate the incoming handles. If validation fails, ensure they are + // destroyed. + std::vector<PlatformHandle> incoming_handles; + std::swap(incoming_handles, incoming_handles_); + + if (extra_header_size < + sizeof(Message::MachPortsExtraHeader) + + (incoming_handles.size() * sizeof(Message::MachPortsEntry))) { + return false; + } + + const auto* mach_ports_header = + reinterpret_cast<const Message::MachPortsExtraHeader*>(extra_header); + if (mach_ports_header->num_ports != incoming_handles.size()) { + return false; + } + + for (uint16_t i = 0; i < mach_ports_header->num_ports; ++i) { + auto type = static_cast<PlatformHandle::Type>( + mach_ports_header->entries[i].mach_entry.type); + if (type == PlatformHandle::Type::kNone) { + return false; + } else if (type == PlatformHandle::Type::kFd && + incoming_handles[i].is_mach_send()) { + int fd = fileport_makefd(incoming_handles[i].GetMachSendRight().get()); + if (fd < 0) { + return false; + } + incoming_handles[i] = PlatformHandle(base::ScopedFD(fd)); + } else if (type != incoming_handles[i].type()) { + return false; + } + } + + *handles = std::move(incoming_handles); + return true; + } + + private: + ~ChannelMac() override = default; + + void StartOnIOThread() { + vm_address_t address = 0; + const vm_size_t size = getpagesize(); + kern_return_t kr = + vm_allocate(mach_task_self(), &address, size, + VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate"; + send_buffer_.reset(address, size); + + kr = vm_allocate(mach_task_self(), &address, size, + VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate"; + receive_buffer_.reset(address, size); + + // When a channel is created, it only has one end of communication (either + // send or receive). If it was created with a receive port, the first thing + // a channel does is receive a special channel-internal message containing + // its peer's send right. If the channel was created with a send right, it + // creates a new receive right and sends to its peer (using the send right + // it was created with) a new send right to the receive right. This + // establishes the bidirectional communication channel. + if (send_port_ != MACH_PORT_NULL) { + DCHECK(receive_port_ == MACH_PORT_NULL); + CHECK(base::mac::CreateMachPort(&receive_port_, nullptr, + MACH_PORT_QLIMIT_LARGE)); + if (!RequestSendDeadNameNotification()) { + OnError(Error::kConnectionFailed); + return; + } + SendHandshake(); + } else if (receive_port_ != MACH_PORT_NULL) { + DCHECK(send_port_ == MACH_PORT_NULL); + // Wait for the received message via the MessageLoop. + } else { + NOTREACHED(); + } + + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); + base::MessageLoopCurrentForIO::Get()->WatchMachReceivePort( + receive_port_.get(), &watch_controller_, this); + } + + void ShutDownOnIOThread() { + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); + + watch_controller_.StopWatchingMachPort(); + + send_buffer_.reset(); + receive_buffer_.reset(); + incoming_handles_.clear(); + + if (leak_handles_) { + ignore_result(receive_port_.release()); + ignore_result(send_port_.release()); + } else { + receive_port_.reset(); + send_port_.reset(); + } + + // May destroy the |this| if it was the last reference. + self_ = nullptr; + } + + // Requests that the kernel notify the |receive_port_| when the receive right + // connected to |send_port_| becomes a dead name. This should be called as + // soon as the Channel establishes both the send and receive ports. + bool RequestSendDeadNameNotification() { + base::mac::ScopedMachSendRight previous; + kern_return_t kr = mach_port_request_notification( + mach_task_self(), send_port_.get(), MACH_NOTIFY_DEAD_NAME, 0, + receive_port_.get(), MACH_MSG_TYPE_MAKE_SEND_ONCE, + base::mac::ScopedMachSendRight::Receiver(previous).get()); + if (kr != KERN_SUCCESS) { + // If port is already a dead name (i.e. the receiver is already gone), + // then the channel should be shut down by the caller. + MACH_LOG_IF(ERROR, kr != KERN_INVALID_ARGUMENT, kr) + << "mach_port_request_notification"; + return false; + } + return true; + } + + // SendHandshake() sends to the |receive_port_| a right to |send_port_|, + // establishing bi-directional communication with the peer. After the + // handshake message has been sent, this Channel can queue any pending + // messages for its peer. + void SendHandshake() { + mach_msg_header_t message{}; + message.msgh_bits = + MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND); + message.msgh_size = sizeof(message); + message.msgh_remote_port = send_port_.get(); + message.msgh_local_port = receive_port_.get(); + message.msgh_id = kChannelMacHandshakeMsgId; + kern_return_t kr = + mach_msg(&message, MACH_SEND_MSG, sizeof(message), 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "mach_msg send handshake"; + + base::AutoLock lock(write_lock_); + OnWriteErrorLocked(Error::kConnectionFailed); + return; + } + + base::AutoLock lock(write_lock_); + handshake_done_ = true; + SendPendingMessagesLocked(); + } + + // Acquires the peer's send right from the handshake message sent via + // SendHandshake(). After this, bi-directional communication is established + // and this Channel can send to its peer any pending messages. + bool ReceiveHandshake(base::BufferIterator<const char> buffer) { + if (handshake_done_) { + OnError(Error::kReceivedMalformedData); + return false; + } + + DCHECK(send_port_ == MACH_PORT_NULL); + + auto* message = buffer.Object<mach_msg_header_t>(); + if (message->msgh_id != kChannelMacHandshakeMsgId || + message->msgh_local_port == MACH_PORT_NULL) { + OnError(Error::kConnectionFailed); + return false; + } + + // Record the audit token of the sender. All messages received by the + // channel must be from this same sender. + auto* trailer = buffer.Object<mach_msg_audit_trailer_t>(); + peer_audit_token_.reset(new audit_token_t); + memcpy(peer_audit_token_.get(), &trailer->msgh_audit, + sizeof(audit_token_t)); + + send_port_ = base::mac::ScopedMachSendRight(message->msgh_remote_port); + + if (!RequestSendDeadNameNotification()) { + OnError(Error::kConnectionFailed); + return false; + } + + base::AutoLock lock(write_lock_); + handshake_done_ = true; + SendPendingMessagesLocked(); + + return true; + } + + void SendPendingMessages() { + base::AutoLock lock(write_lock_); + SendPendingMessagesLocked(); + } + + void SendPendingMessagesLocked() { + // If a previous send failed due to the receiver's kernel message queue + // being full, attempt to send that failed message first. + if (send_buffer_contains_message_ && !reject_writes_) { + auto* header = + reinterpret_cast<mach_msg_header_t*>(send_buffer_.address()); + if (!MachMessageSendLocked(header)) { + // The send failed again. If the peer is still unable to receive, + // MachMessageSendLocked() will have arranged another attempt. If an + // error occurred, the channel will be shut down. + return; + } + } + + // Try and send any other pending messages that were queued. + while (!pending_messages_.empty() && !reject_writes_) { + bool did_send = SendMessageLocked(std::move(pending_messages_.front())); + // If the message failed to send because the kernel message queue is + // full, the message will have been fully serialized and + // |send_buffer_contains_message_| will be set to true. The Mojo message + // object can be destroyed at this point. + pending_messages_.pop_front(); + if (!did_send) + break; + } + } + + bool SendMessageLocked(MessagePtr message) { + DCHECK(!send_buffer_contains_message_); + base::BufferIterator<char> buffer( + reinterpret_cast<char*>(send_buffer_.address()), send_buffer_.size()); + + auto* header = buffer.MutableObject<mach_msg_header_t>(); + *header = mach_msg_header_t{}; + + // Compute the total size of the message. If the message data are larger + // than the allocated receive buffer, the data will be transferred out-of- + // line. The receive buffer is the same size as the send buffer, but there + // also needs to be room to receive the trailer. + const size_t mach_header_size = + sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) + + (message->num_handles() * sizeof(mach_msg_port_descriptor_t)); + const size_t expected_message_size = + round_msg(mach_header_size + message->data_num_bytes() + + sizeof(mach_msg_audit_trailer_t)); + const bool transfer_message_ool = + expected_message_size >= send_buffer_.size(); + + const bool is_complex = message->has_handles() || transfer_message_ool; + + header->msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) | + (is_complex ? MACH_MSGH_BITS_COMPLEX : 0); + header->msgh_remote_port = send_port_.get(); + header->msgh_id = + transfer_message_ool ? kChannelMacOOLMsgId : kChannelMacInlineMsgId; + + auto* body = buffer.MutableObject<mach_msg_body_t>(); + body->msgh_descriptor_count = message->num_handles(); + + std::vector<PlatformHandleInTransit> handles = message->TakeHandles(); + auto descriptors = + buffer.MutableSpan<mach_msg_port_descriptor_t>(handles.size()); + for (size_t i = 0; i < message->num_handles(); ++i) { + auto* descriptor = &descriptors[i]; + descriptor->pad1 = 0; + descriptor->pad2 = 0; + descriptor->type = MACH_MSG_PORT_DESCRIPTOR; + + PlatformHandle handle = handles[i].TakeHandle(); + + switch (handle.type()) { + case PlatformHandle::Type::kMachSend: + descriptor->name = handle.ReleaseMachSendRight(); + descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND; + break; + case PlatformHandle::Type::kMachReceive: + descriptor->name = handle.ReleaseMachReceiveRight(); + descriptor->disposition = MACH_MSG_TYPE_MOVE_RECEIVE; + break; + case PlatformHandle::Type::kFd: { + // After putting the FD in a fileport, the kernel will keep a + // reference to the opened file, and the local descriptor can be + // closed. + kern_return_t kr = + fileport_makeport(handle.GetFD().get(), &descriptor->name); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "fileport_makeport"; + OnWriteErrorLocked(Error::kDisconnected); + return false; + } + descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND; + break; + } + default: + NOTREACHED() << "Unsupported handle type " + << static_cast<int>(handle.type()); + OnWriteErrorLocked(Error::kDisconnected); + } + } + + if (transfer_message_ool) { + auto* descriptor = buffer.MutableObject<mach_msg_ool_descriptor_t>(); + descriptor->address = const_cast<void*>(message->data()); + descriptor->size = message->data_num_bytes(); + descriptor->copy = MACH_MSG_VIRTUAL_COPY; + descriptor->deallocate = false; + descriptor->pad1 = 0; + descriptor->type = MACH_MSG_OOL_DESCRIPTOR; + ++body->msgh_descriptor_count; + } else { + auto* data_size = buffer.MutableObject<uint64_t>(); + *data_size = message->data_num_bytes(); + + auto data = buffer.MutableSpan<char>(message->data_num_bytes()); + memcpy(data.data(), message->data(), message->data_num_bytes()); + } + + header->msgh_size = round_msg(buffer.position()); + return MachMessageSendLocked(header); + } + + bool MachMessageSendLocked(mach_msg_header_t* header) { + kern_return_t kr = mach_msg(header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, + header->msgh_size, 0, MACH_PORT_NULL, + /*timeout=*/0, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + if (kr == MACH_SEND_TIMED_OUT) { + // The kernel message queue for the peer's receive port is full, so the + // send timed out. Since the send buffer contains a fully serialized + // message, set a flag to indicate this condition and arrange to try + // sending it again. + send_buffer_contains_message_ = true; + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChannelMac::SendPendingMessages, this)); + } else { + // If the message failed to send for other reasons, destroy it and + // close the channel. + MACH_LOG_IF(ERROR, kr != MACH_SEND_INVALID_DEST, kr) << "mach_msg send"; + send_buffer_contains_message_ = false; + mach_msg_destroy(header); + OnWriteErrorLocked(Error::kDisconnected); + } + return false; + } + + send_buffer_contains_message_ = false; + return true; + } + + // base::MessageLoopCurrent::DestructionObserver: + void WillDestroyCurrentMessageLoop() override { + DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); + if (self_) + ShutDownOnIOThread(); + } + + // base::MessagePumpKqueue::MachPortWatcher: + void OnMachMessageReceived(mach_port_t port) override { + DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); + + base::BufferIterator<const char> buffer( + reinterpret_cast<const char*>(receive_buffer_.address()), + receive_buffer_.size()); + auto* header = buffer.MutableObject<mach_msg_header_t>(); + *header = mach_msg_header_t{}; + header->msgh_size = buffer.total_size(); + header->msgh_local_port = receive_port_.get(); + + const mach_msg_option_t rcv_options = + MACH_RCV_MSG | MACH_RCV_TIMEOUT | + MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT); + kern_return_t kr = + mach_msg(header, rcv_options, 0, header->msgh_size, receive_port_.get(), + /*timeout=*/0, MACH_PORT_NULL); + if (kr != KERN_SUCCESS) { + if (kr == MACH_RCV_TIMED_OUT) + return; + MACH_LOG(ERROR, kr) << "mach_msg receive"; + OnError(Error::kDisconnected); + return; + } + + base::ScopedMachMsgDestroy scoped_message(header); + + if (header->msgh_id == kChannelMacHandshakeMsgId) { + buffer.Seek(0); + if (ReceiveHandshake(buffer)) + scoped_message.Disarm(); + return; + } + + if (header->msgh_id == MACH_NOTIFY_DEAD_NAME) { + // The DEAD_NAME notification contains a port right that must be + // explicitly destroyed, as it is not carried in a descriptor. + buffer.Seek(0); + auto* notification = buffer.Object<mach_dead_name_notification_t>(); + + // Verify that the kernel sent the notification. + buffer.Seek(notification->not_header.msgh_size); + auto* trailer = buffer.Object<mach_msg_audit_trailer_t>(); + static const audit_token_t kernel_audit_token = KERNEL_AUDIT_TOKEN_VALUE; + if (memcmp(&trailer->msgh_audit, &kernel_audit_token, + sizeof(audit_token_t)) == 0) { + DCHECK(notification->not_port == send_port_); + // Release the notification's send right using this scoper. + base::mac::ScopedMachSendRight notify_port(notification->not_port); + } + OnError(Error::kDisconnected); + return; + } else if (header->msgh_id == MACH_NOTIFY_SEND_ONCE) { + // Notification of an extant send-once right being destroyed. This is + // sent for the right allocated in RequestSendDeadNameNotification(), + // and no action needs to be taken. Since it is ignored, the kernel + // audit token need not be checked. + return; + } + + if (header->msgh_size < sizeof(mach_msg_base_t)) { + OnError(Error::kReceivedMalformedData); + return; + } + + if (peer_audit_token_) { + buffer.Seek(header->msgh_size); + auto* trailer = buffer.Object<mach_msg_audit_trailer_t>(); + if (memcmp(&trailer->msgh_audit, peer_audit_token_.get(), + sizeof(audit_token_t)) != 0) { + // Do not shut down the channel because this endpoint could be + // accessible via the bootstrap server, which means anyone could send + // messages to it. + LOG(ERROR) << "Rejecting message from unauthorized peer"; + return; + } + buffer.Seek(sizeof(*header)); + } + + auto* body = buffer.Object<mach_msg_body_t>(); + if (((header->msgh_bits & MACH_MSGH_BITS_COMPLEX) != 0) != + (body->msgh_descriptor_count > 0)) { + LOG(ERROR) << "Message complex bit does not match descriptor count"; + OnError(Error::kReceivedMalformedData); + return; + } + + bool transfer_message_ool = false; + mach_msg_size_t mojo_handle_count = body->msgh_descriptor_count; + if (header->msgh_id == kChannelMacOOLMsgId) { + transfer_message_ool = true; + // The number of Mojo handles to process will be one fewer, since the + // message itself was transferred using OOL memory. + if (body->msgh_descriptor_count < 1) { + LOG(ERROR) << "OOL message does not have descriptor"; + OnError(Error::kReceivedMalformedData); + return; + } + --mojo_handle_count; + } else if (header->msgh_id != kChannelMacInlineMsgId) { + OnError(Error::kReceivedMalformedData); + return; + } + + incoming_handles_.clear(); + incoming_handles_.reserve(mojo_handle_count); + + // Accept the descriptors into |incoming_handles_|. They will be validated + // in GetReadPlatformHandles(). If the handle is accepted, the name in the + // descriptor is cleared, so that it is not double-unrefed if the + // |scoped_message| destroys the message on error. + auto descriptors = + buffer.MutableSpan<mach_msg_port_descriptor_t>(mojo_handle_count); + for (auto& descriptor : descriptors) { + if (descriptor.type != MACH_MSG_PORT_DESCRIPTOR) { + LOG(ERROR) << "Incorrect descriptor type " << descriptor.type; + OnError(Error::kReceivedMalformedData); + return; + } + switch (descriptor.disposition) { + case MACH_MSG_TYPE_MOVE_SEND: + incoming_handles_.emplace_back( + base::mac::ScopedMachSendRight(descriptor.name)); + descriptor.name = MACH_PORT_NULL; + break; + case MACH_MSG_TYPE_MOVE_RECEIVE: + incoming_handles_.emplace_back( + base::mac::ScopedMachReceiveRight(descriptor.name)); + descriptor.name = MACH_PORT_NULL; + break; + default: + DLOG(ERROR) << "Unhandled descriptor disposition " + << descriptor.disposition; + OnError(Error::kReceivedMalformedData); + return; + } + } + + base::span<const char> payload; + base::mac::ScopedMachVM ool_memory; + if (transfer_message_ool) { + auto* descriptor = buffer.Object<mach_msg_ool_descriptor_t>(); + if (descriptor->type != MACH_MSG_OOL_DESCRIPTOR) { + LOG(ERROR) << "Incorrect descriptor type " << descriptor->type; + OnError(Error::kReceivedMalformedData); + return; + } + + payload = base::span<const char>( + reinterpret_cast<const char*>(descriptor->address), descriptor->size); + // The kernel page-aligns the OOL memory when performing the mach_msg on + // the send side, but it preserves the original size in the descriptor. + ool_memory.reset_unaligned( + reinterpret_cast<vm_address_t>(descriptor->address), + descriptor->size); + } else { + auto* data_size_ptr = buffer.Object<uint64_t>(); + payload = buffer.Span<const char>(*data_size_ptr); + } + + if (payload.empty()) { + OnError(Error::kReceivedMalformedData); + return; + } + + scoped_message.Disarm(); + + size_t ignored; + DispatchResult result = TryDispatchMessage(payload, &ignored); + if (result != DispatchResult::kOK) { + OnError(Error::kReceivedMalformedData); + return; + } + } + + // Marks the channel as unaccepting of new messages and shuts it down. + void OnWriteErrorLocked(Error error) { + reject_writes_ = true; + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChannelMac::OnError, this, error)); + } + + // Keeps the Channel alive at least until explicit shutdown on the IO thread. + scoped_refptr<ChannelMac> self_; + + scoped_refptr<base::TaskRunner> io_task_runner_; + + base::mac::ScopedMachReceiveRight receive_port_; + base::mac::ScopedMachSendRight send_port_; + + // Whether to leak the above Mach ports when the channel is shut down. + bool leak_handles_ = false; + + // Whether or not the channel-internal handshake, which establishes bi- + // directional communication, is complete. If false, calls to Write() will + // enqueue messages on |pending_messages_|. + bool handshake_done_ = false; + + // If the channel was created with a receive right, the first message it + // receives is the internal handshake. The audit token of the sender of the + // handshake is recorded here, and all future messages are required to be + // from that sender. + std::unique_ptr<audit_token_t> peer_audit_token_; + + // IO buffer for receiving Mach messages. Only accessed on |io_task_runner_|. + base::mac::ScopedMachVM receive_buffer_; + + // Handles that were received with a message that are validated and returned + // in GetReadPlatformHandles(). Only accessed on |io_task_runner_|. + std::vector<PlatformHandle> incoming_handles_; + + // Watch controller for |receive_port_|, calls OnMachMessageReceived() when + // new messages are available. + base::MessagePumpForIO::MachPortWatchController watch_controller_; + + // Lock that protects the following members. + base::Lock write_lock_; + // Whether writes should be rejected due to an internal error. + bool reject_writes_ = false; + // IO buffer for sending Mach messages. + base::mac::ScopedMachVM send_buffer_; + // If a message timed out during send in MachMessageSendLocked(), this will + // be true to indicate that |send_buffer_| contains a message that must + // be sent. If this is true, then other calls to Write() queue messages onto + // |pending_messages_|. + bool send_buffer_contains_message_ = false; + // When |handshake_done_| is false or |send_buffer_contains_message_| is true, + // calls to Write() will enqueue messages here. + base::circular_deque<MessagePtr> pending_messages_; + + DISALLOW_COPY_AND_ASSIGN(ChannelMac); +}; + +} // namespace + +// TODO(crbug.com/932175): This will be renamed Channel::Create. +MOJO_SYSTEM_IMPL_EXPORT +scoped_refptr<Channel> ChannelMacCreate( + Channel::Delegate* delegate, + ConnectionParams connection_params, + Channel::HandlePolicy handle_policy, + scoped_refptr<base::TaskRunner> io_task_runner) { + return new ChannelMac(delegate, std::move(connection_params), handle_policy, + io_task_runner); +} + +} // namespace core +} // namespace mojo diff --git a/chromium/mojo/core/channel_mac_fuzzer.cc b/chromium/mojo/core/channel_mac_fuzzer.cc new file mode 100644 index 00000000000..e45e6bbe5c2 --- /dev/null +++ b/chromium/mojo/core/channel_mac_fuzzer.cc @@ -0,0 +1,136 @@ +// Copyright 2019 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 <list> + +#include "base/logging.h" +#include "base/mac/mach_logging.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "mojo/core/channel.h" +#include "mojo/core/entrypoints.h" +#include "mojo/core/test/data/channel_mac/channel_mac.pb.h" +#include "mojo/public/cpp/platform/features.h" +#include "mojo/public/cpp/platform/platform_channel.h" +#include "testing/libfuzzer/fuzzers/mach/mach_message_converter.h" +#include "testing/libfuzzer/proto/lpm_interface.h" + +namespace { + +class ChannelMacFuzzer { + public: + ChannelMacFuzzer() { + feature_list_.InitAndEnableFeature(mojo::features::kMojoChannelMac); + + mojo::core::InitializeCore(); + + logging::SetMinLogLevel(logging::LOG_FATAL); + } + + scoped_refptr<base::TaskRunner> io_task_runner() { + return message_loop_.task_runner(); + } + + private: + base::test::ScopedFeatureList feature_list_; + base::MessageLoopForIO message_loop_; +}; + +class FakeChannelDelegate : public mojo::core::Channel::Delegate { + public: + FakeChannelDelegate() = default; + ~FakeChannelDelegate() override = default; + + void OnChannelMessage(const void* payload, + size_t payload_size, + std::vector<mojo::PlatformHandle> handles) override {} + void OnChannelError(mojo::core::Channel::Error error) override {} +}; + +} // namespace + +DEFINE_BINARY_PROTO_FUZZER(mojo_fuzzer::ChannelMac proto) { + static ChannelMacFuzzer environment; + + mojo::PlatformChannel platform_channel; + mojo::PlatformChannelEndpoint fuzzed_endpoint; + mojo::PlatformChannelEndpoint other_endpoint; + + mach_port_t send_port = platform_channel.local_endpoint() + .platform_handle() + .GetMachSendRight() + .get(); + + if (proto.endpoint_type() == mojo_fuzzer::ChannelMac_EndpointType_LOCAL) { + fuzzed_endpoint = platform_channel.TakeLocalEndpoint(); + other_endpoint = platform_channel.TakeRemoteEndpoint(); + } else if (proto.endpoint_type() == + mojo_fuzzer::ChannelMac_EndpointType_REMOTE) { + fuzzed_endpoint = platform_channel.TakeRemoteEndpoint(); + other_endpoint = platform_channel.TakeLocalEndpoint(); + } + + FakeChannelDelegate delegate; + + auto channel = mojo::core::Channel::Create( + &delegate, mojo::core::ConnectionParams(std::move(fuzzed_endpoint)), + mojo::core::Channel::HandlePolicy::kAcceptHandles, + environment.io_task_runner()); + channel->Start(); + + // If the handshake is not being fuzzed, establish a peer Channel that will + // put |channel| into a good state by performing the handshake. + scoped_refptr<mojo::core::Channel> peer_channel; + if (!proto.fuzz_handshake()) { + peer_channel = mojo::core::Channel::Create( + &delegate, mojo::core::ConnectionParams(std::move(other_endpoint)), + mojo::core::Channel::HandlePolicy::kAcceptHandles, + environment.io_task_runner()); + peer_channel->Start(); + } + + base::RunLoop().RunUntilIdle(); + + // Save off any ports that were sent as part of a message until after the + // channel has been shut down. + std::list<mach_fuzzer::SendablePort> ports_to_destroy; + + for (auto& message : *proto.mutable_messages()) { + if (message.HasExtension(mojo_fuzzer::MojoMessage::mojo_message)) { + // Mojo message data for inline Mach messages is + // [data_length_uint64][data_bytes]. + const auto& mojo_message = + message.GetExtension(mojo_fuzzer::MojoMessage::mojo_message); + + // If the fuzz data do not specify an explicit length, just use the byte + // length. + uint64_t data_length = mojo_message.has_data_length() + ? mojo_message.data_length() + : mojo_message.data().size(); + std::string data; + data.append(reinterpret_cast<const char*>(&data_length), + sizeof(data_length)); + data.append(mojo_message.data().begin(), mojo_message.data().end()); + message.set_data(data); + } + + mach_fuzzer::SendResult result = SendMessage(send_port, message); + + std::move(result.message.ports.begin(), result.message.ports.end(), + std::back_inserter(ports_to_destroy)); + } + + base::RunLoop().RunUntilIdle(); + + channel->ShutDown(); + channel.reset(); + + if (peer_channel) { + peer_channel->ShutDown(); + peer_channel.reset(); + } + + base::RunLoop().RunUntilIdle(); +} diff --git a/chromium/mojo/core/channel_posix.cc b/chromium/mojo/core/channel_posix.cc index 2ef2a5fcfe3..eed78a3c7f4 100644 --- a/chromium/mojo/core/channel_posix.cc +++ b/chromium/mojo/core/channel_posix.cc @@ -22,6 +22,7 @@ #include "base/task_runner.h" #include "build/build_config.h" #include "mojo/core/core.h" +#include "mojo/public/cpp/platform/features.h" #include "mojo/public/cpp/platform/socket_utils_posix.h" #if !defined(OS_NACL) @@ -53,12 +54,7 @@ class MessageView { MessageView(MessageView&& other) { *this = std::move(other); } - MessageView& operator=(MessageView&& other) { - message_ = std::move(other.message_); - offset_ = other.offset_; - handles_ = std::move(other.handles_); - return *this; - } + MessageView& operator=(MessageView&& other) = default; ~MessageView() {} @@ -232,9 +228,9 @@ class ChannelPosix : public Channel, const bool extract_send_rights = remote_process().is_valid(); for (size_t i = 0, mach_port_index = 0; i < num_handles; ++i) { if (mach_port_index < num_mach_ports && - mach_ports[mach_port_index].index == i) { - mach_port_t port_name = - static_cast<mach_port_t>(mach_ports[mach_port_index].mach_port); + mach_ports[mach_port_index].posix_entry.index == i) { + mach_port_t port_name = static_cast<mach_port_t>( + mach_ports[mach_port_index].posix_entry.mach_port); if (extract_send_rights) { handles_in_transit[i] = PlatformHandleInTransit::CreateForMachPortName(port_name); @@ -780,12 +776,27 @@ class ChannelPosix : public Channel, } // namespace +#if defined(OS_MACOSX) && !defined(OS_IOS) +// Forward declare from channel_mac.cc. +scoped_refptr<Channel> ChannelMacCreate( + Channel::Delegate* delegate, + ConnectionParams connection_params, + Channel::HandlePolicy handle_policy, + scoped_refptr<base::TaskRunner> io_task_runner); +#endif + // static scoped_refptr<Channel> Channel::Create( Delegate* delegate, ConnectionParams connection_params, HandlePolicy handle_policy, scoped_refptr<base::TaskRunner> io_task_runner) { +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + return ChannelMacCreate(delegate, std::move(connection_params), + handle_policy, io_task_runner); + } +#endif return new ChannelPosix(delegate, std::move(connection_params), handle_policy, io_task_runner); } diff --git a/chromium/mojo/core/channel_unittest.cc b/chromium/mojo/core/channel_unittest.cc index d5b37dce383..14585e348ea 100644 --- a/chromium/mojo/core/channel_unittest.cc +++ b/chromium/mojo/core/channel_unittest.cc @@ -4,6 +4,8 @@ #include "mojo/core/channel.h" +#include <atomic> + #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" @@ -362,6 +364,127 @@ TEST(ChannelTest, DeserializeMessage_BadExtraHeaderSize) { base::kNullProcessHandle)); } +class CountingChannelDelegate : public Channel::Delegate { + public: + explicit CountingChannelDelegate(base::OnceClosure on_final_message) + : on_final_message_(std::move(on_final_message)) {} + ~CountingChannelDelegate() override = default; + + void OnChannelMessage(const void* payload, + size_t payload_size, + std::vector<PlatformHandle> handles) override { + // If this is the special "final message", run the closure. + if (payload_size == 1) { + auto* payload_str = reinterpret_cast<const char*>(payload); + if (payload_str[0] == '!') { + std::move(on_final_message_).Run(); + return; + } + } + + ++message_count_; + } + + void OnChannelError(Channel::Error error) override { ++error_count_; } + + size_t message_count_ = 0; + size_t error_count_ = 0; + + private: + base::OnceClosure on_final_message_; +}; + +TEST(ChannelTest, PeerStressTest) { + constexpr size_t kLotsOfMessages = 1024; + + base::MessageLoop message_loop(base::MessageLoop::TYPE_IO); + base::RunLoop run_loop; + + // Both channels should receive all the messages that each is sent. When + // the count becomes 2 (indicating both channels have received the final + // message), quit the main test thread's run loop. + std::atomic_int count_channels_received_final_message(0); + auto quit_when_both_channels_received_final_message = base::BindRepeating( + [](std::atomic_int* count_channels_received_final_message, + base::OnceClosure quit_closure) { + if (++(*count_channels_received_final_message) == 2) { + std::move(quit_closure).Run(); + } + }, + base::Unretained(&count_channels_received_final_message), + run_loop.QuitClosure()); + + // Create a second IO thread for the peer channel. + base::Thread::Options thread_options; + thread_options.message_loop_type = base::MessageLoop::TYPE_IO; + base::Thread peer_thread("peer_b_io"); + peer_thread.StartWithOptions(thread_options); + + // Create two channels that run on separate threads. + PlatformChannel platform_channel; + + CountingChannelDelegate delegate_a( + quit_when_both_channels_received_final_message); + scoped_refptr<Channel> channel_a = Channel::Create( + &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()), + Channel::HandlePolicy::kRejectHandles, message_loop.task_runner()); + + CountingChannelDelegate delegate_b( + quit_when_both_channels_received_final_message); + scoped_refptr<Channel> channel_b = Channel::Create( + &delegate_b, ConnectionParams(platform_channel.TakeRemoteEndpoint()), + Channel::HandlePolicy::kRejectHandles, peer_thread.task_runner()); + + // Send a lot of messages, followed by a final terminating message. + auto send_lots_of_messages = [](scoped_refptr<Channel> channel) { + for (size_t i = 0; i < kLotsOfMessages; ++i) { + channel->Write(std::make_unique<Channel::Message>(0, 0)); + } + }; + auto send_final_message = [](scoped_refptr<Channel> channel) { + auto message = std::make_unique<Channel::Message>(1, 0); + auto* payload = static_cast<char*>(message->mutable_payload()); + payload[0] = '!'; + channel->Write(std::move(message)); + }; + + channel_a->Start(); + channel_b->Start(); + + send_lots_of_messages(channel_a); + send_lots_of_messages(channel_b); + + message_loop.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a)); + message_loop.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a)); + message_loop.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_final_message, channel_a)); + + peer_thread.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_lots_of_messages, channel_b)); + peer_thread.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_lots_of_messages, channel_b)); + peer_thread.task_runner()->PostTask( + FROM_HERE, base::BindOnce(send_final_message, channel_b)); + + // Run until quit_when_both_channels_received_final_message quits the loop. + run_loop.Run(); + + channel_a->ShutDown(); + channel_b->ShutDown(); + + peer_thread.StopSoon(); + + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(kLotsOfMessages * 3, delegate_a.message_count_); + EXPECT_EQ(kLotsOfMessages * 3, delegate_b.message_count_); + + EXPECT_EQ(0u, delegate_a.error_count_); + EXPECT_EQ(0u, delegate_b.error_count_); +} + } // namespace } // namespace core } // namespace mojo diff --git a/chromium/mojo/core/embedder_unittest.cc b/chromium/mojo/core/embedder_unittest.cc index f336f4c8f70..8d90cc2690d 100644 --- a/chromium/mojo/core/embedder_unittest.cc +++ b/chromium/mojo/core/embedder_unittest.cc @@ -293,7 +293,7 @@ TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) { WriteMessageWithHandles(server_mp, "hello", &sb2, 1); // 4. Read a message from |server_mp|. - EXPECT_EQ("bye", ReadMessage(server_mp)); + EXPECT_EQ("hey", ReadMessage(server_mp)); // 5. Expect that the contents of the shared buffer have changed. EXPECT_EQ(kByeWorld, std::string(buffer)); @@ -305,6 +305,9 @@ TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) { EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(mapping.memory()))); ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1)); + + // Tell the child it's safe to shut down. + WriteMessage(server_mp, "bye"); }); } @@ -327,7 +330,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient, // 4. Write into |buffer| and send a message back. memcpy(buffer, kByeWorld, sizeof(kByeWorld)); - WriteMessage(client_mp, "bye"); + WriteMessage(client_mp, "hey"); // 5. Extract the shared memory handle and ensure we can map it and read the // contents. @@ -338,6 +341,8 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient, EXPECT_NE(buffer, mapping.memory()); EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(mapping.memory()))); + EXPECT_EQ("bye", ReadMessage(client_mp)); + // 6. Close |sb1|. Should fail because |ExtractRegionFromSharedBuffer()| // should have closed the handle. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(sb1)); diff --git a/chromium/mojo/core/invitation_unittest.cc b/chromium/mojo/core/invitation_unittest.cc index 58603897535..dae047ad6c9 100644 --- a/chromium/mojo/core/invitation_unittest.cc +++ b/chromium/mojo/core/invitation_unittest.cc @@ -22,6 +22,7 @@ #include "build/build_config.h" #include "mojo/core/test/mojo_test_base.h" #include "mojo/public/c/system/invitation.h" +#include "mojo/public/cpp/platform/features.h" #include "mojo/public/cpp/platform/named_platform_channel.h" #include "mojo/public/cpp/platform/platform_channel.h" #include "mojo/public/cpp/system/platform_handle.h" @@ -78,6 +79,19 @@ void PrepareToPassRemoteEndpoint(PlatformChannel* channel, std::string value; #if defined(OS_FUCHSIA) channel->PrepareToPassRemoteEndpoint(&options->handles_to_transfer, &value); +#elif defined(OS_MACOSX) + PlatformChannel::HandlePassingInfo info; + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) + info = options->mach_ports_for_rendezvous; + else + info = options->fds_to_remap; + + channel->PrepareToPassRemoteEndpoint(&info, &value); + + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) + options->mach_ports_for_rendezvous = info; + else + options->fds_to_remap = info; #elif defined(OS_POSIX) channel->PrepareToPassRemoteEndpoint(&options->fds_to_remap, &value); #elif defined(OS_WIN) diff --git a/chromium/mojo/core/ports/name.h b/chromium/mojo/core/ports/name.h index 415ba65a958..0dafee2720e 100644 --- a/chromium/mojo/core/ports/name.h +++ b/chromium/mojo/core/ports/name.h @@ -11,7 +11,7 @@ #include <tuple> #include "base/component_export.h" -#include "base/hash.h" +#include "base/hash/hash.h" namespace mojo { namespace core { diff --git a/chromium/mojo/core/ports/node.cc b/chromium/mojo/core/ports/node.cc index 64989c2948b..767e37ce305 100644 --- a/chromium/mojo/core/ports/node.cc +++ b/chromium/mojo/core/ports/node.cc @@ -879,7 +879,7 @@ int Node::MergePortsInternal(const PortRef& port0_ref, { // Needed to swap peer map entries below. PortLocker::AssertNoPortsLockedOnCurrentThread(); - base::Optional<base::AutoLock> ports_locker(base::in_place, ports_lock_); + base::ReleasableAutoLock ports_locker(&ports_lock_); base::Optional<PortLocker> locker(base::in_place, port_refs, 2); auto* port0 = locker->GetPort(port0_ref); @@ -910,7 +910,7 @@ int Node::MergePortsInternal(const PortRef& port0_ref, const bool close_port1 = port1->state == Port::kReceiving || allow_close_on_bad_state; locker.reset(); - ports_locker.reset(); + ports_locker.Release(); if (close_port0) ClosePort(port0_ref); if (close_port1) diff --git a/chromium/mojo/core/test/BUILD.gn b/chromium/mojo/core/test/BUILD.gn index 6fad6fec711..5e18e02740a 100644 --- a/chromium/mojo/core/test/BUILD.gn +++ b/chromium/mojo/core/test/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//third_party/protobuf/proto_library.gni") + static_library("test_support") { testonly = true sources = [ @@ -86,3 +88,15 @@ static_library("test_support_impl") { "test_support_impl.h", ] } + +if (is_mac) { + proto_library("channel_mac_proto") { + sources = [ + "data/channel_mac/channel_mac.proto", + ] + deps = [ + "//testing/libfuzzer/fuzzers/mach:proto", + ] + import_dirs = [ "//testing/libfuzzer/fuzzers/mach" ] + } +} diff --git a/chromium/mojo/core/watcher_dispatcher.cc b/chromium/mojo/core/watcher_dispatcher.cc index f2eb2e253d7..00d2a431036 100644 --- a/chromium/mojo/core/watcher_dispatcher.cc +++ b/chromium/mojo/core/watcher_dispatcher.cc @@ -7,6 +7,7 @@ #include <algorithm> #include <limits> +#include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -58,6 +59,9 @@ void WatcherDispatcher::NotifyHandleClosed(Dispatcher* dispatcher) { watch->Cancel(); } +// handler_ may be address-taken in a different DSO, and hence incompatible with +// CFI-icall. +NO_SANITIZE("cfi-icall") void WatcherDispatcher::InvokeWatchCallback(uintptr_t context, MojoResult result, const HandleSignalsState& state, diff --git a/chromium/mojo/public/BUILD.gn b/chromium/mojo/public/BUILD.gn index bd094c8c328..b7d5d05b3a1 100644 --- a/chromium/mojo/public/BUILD.gn +++ b/chromium/mojo/public/BUILD.gn @@ -8,6 +8,7 @@ group("public") { deps = [ ":sdk", "cpp/bindings", + "cpp/test:test_mojom", "interfaces/bindings/tests:test_interfaces", ] diff --git a/chromium/mojo/public/c/system/macros.h b/chromium/mojo/public/c/system/macros.h index 7786094e250..1023e1c111a 100644 --- a/chromium/mojo/public/c/system/macros.h +++ b/chromium/mojo/public/c/system/macros.h @@ -7,41 +7,27 @@ #include <stddef.h> +#if !defined(__cplusplus) +#include <assert.h> // Defines static_assert() in C11. +#include <stdalign.h> // Defines alignof() in C11. +#endif + // Assert things at compile time. (|msg| should be a valid identifier name.) // Use like: // MOJO_STATIC_ASSERT(sizeof(struct Foo) == 12, "Foo has invalid size"); -#if defined(__cplusplus) #define MOJO_STATIC_ASSERT(expr, msg) static_assert(expr, msg) -#elif defined(__clang__) -// TODO(thakis): Use #include <assert.h> and static_assert() in C11 mode -// (__STDC_VERSION__>= 201112L) once https://reviews.llvm.org/D17444 made its -// way into Chromium. -#define MOJO_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg) -#else -#define MOJO_STATIC_ASSERT(expr, msg) -#endif // Defines a pointer-sized struct field of the given type. This ensures that the // field has an 8-byte footprint on both 32-bit and 64-bit systems, using an -// anonymous bitfield of either 32 or 0 bits, depending on pointer size. Weird -// formatting here courtesy of clang-format. +// anonymous bitfield of either 32 or 0 bits, depending on pointer size. +// clang-format off #define MOJO_POINTER_FIELD(type, name) \ type name; \ - uint32_t: \ - (sizeof(void*) == 4 ? 32 : 0) + uint32_t : (sizeof(void*) == 4 ? 32 : 0) +// clang-format on // Like the C++11 |alignof| operator. -#if __cplusplus >= 201103L #define MOJO_ALIGNOF(type) alignof(type) -#elif defined(__GNUC__) -#define MOJO_ALIGNOF(type) __alignof__(type) -#elif defined(_MSC_VER) -// The use of |sizeof| is to work around a bug in MSVC 2010 (see -// http://goo.gl/isH0C; supposedly fixed since then). -#define MOJO_ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) -#else -#error "Please define MOJO_ALIGNOF() for your compiler." -#endif // Specify the alignment of a |struct|, etc. // Use like: @@ -49,7 +35,9 @@ // Unlike the C++11 |alignas()|, |alignment| must be an integer. It may not be a // type, nor can it be an expression like |MOJO_ALIGNOF(type)| (due to the // non-C++11 MSVS version). -#if __cplusplus >= 201103L +// This can't use alignas() in C11 mode because unlike the C++11 version the +// C11 version can't be used on struct declarations. +#if defined(__cplusplus) #define MOJO_ALIGNAS(alignment) alignas(alignment) #elif defined(__GNUC__) #define MOJO_ALIGNAS(alignment) __attribute__((aligned(alignment))) diff --git a/chromium/mojo/public/cpp/base/values_mojom_traits.h b/chromium/mojo/public/cpp/base/values_mojom_traits.h index cdb9bbbd94d..66752b7c90d 100644 --- a/chromium/mojo/public/cpp/base/values_mojom_traits.h +++ b/chromium/mojo/public/cpp/base/values_mojom_traits.h @@ -86,8 +86,13 @@ struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS) return mojo_base::mojom::ValueDataView::Tag::DICTIONARY_VALUE; case base::Value::Type::LIST: return mojo_base::mojom::ValueDataView::Tag::LIST_VALUE; + // TODO(crbug.com/859477): Remove after root cause is found. + case base::Value::Type::DEAD: + CHECK(false); + return mojo_base::mojom::ValueDataView::Tag::NULL_VALUE; } - NOTREACHED(); + // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found. + CHECK(false); return mojo_base::mojom::ValueDataView::Tag::NULL_VALUE; } diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn index 52082de79a6..f95d4fbfda4 100644 --- a/chromium/mojo/public/cpp/bindings/BUILD.gn +++ b/chromium/mojo/public/cpp/bindings/BUILD.gn @@ -120,8 +120,6 @@ component("bindings") { "associated_interface_request.h", "binding.h", "binding_set.h", - "call_internal.cc", - "call_internal.h", "callback_helpers.h", "connection_error_callback.h", "connector.h", @@ -171,6 +169,7 @@ component("bindings") { "pipe_control_message_proxy.h", "raw_ptr_impl_ref_traits.h", "receiver.h", + "receiver_set.h", "remote.h", "sequence_local_sync_event_watcher.h", "strong_associated_binding.h", diff --git a/chromium/mojo/public/cpp/bindings/README.md b/chromium/mojo/public/cpp/bindings/README.md index 75ef5a7702a..55a366c45fc 100644 --- a/chromium/mojo/public/cpp/bindings/README.md +++ b/chromium/mojo/public/cpp/bindings/README.md @@ -657,7 +657,7 @@ Similarly to [structs](#Structs), tagged unions generate an identically named, representative C++ class which is typically wrapped in a `mojo::StructPtr<T>`. Unlike structs, all generated union fields are private and must be retrieved and -manipulated using accessors. A field `foo` is accessible by `foo()` and +manipulated using accessors. A field `foo` is accessible by `get_foo()` and settable by `set_foo()`. There is also a boolean `is_foo()` for each field which indicates whether the union is currently taking on the value of field `foo` in exclusion to all other union fields. diff --git a/chromium/mojo/public/cpp/bindings/call_internal.cc b/chromium/mojo/public/cpp/bindings/call_internal.cc deleted file mode 100644 index 8e4e57eeea2..00000000000 --- a/chromium/mojo/public/cpp/bindings/call_internal.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2019 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 "mojo/public/cpp/bindings/call_internal.h" - -namespace mojo { -namespace internal { - -CallProxyWrapperBase::CallProxyWrapperBase(void* proxy) : proxy_(proxy) {} - -CallProxyWrapperBase::CallProxyWrapperBase(CallProxyWrapperBase&& other) - : proxy_(other.proxy_) {} - -CallProxyWrapperBase::~CallProxyWrapperBase() = default; - -} // namespace internal -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/call_internal.h b/chromium/mojo/public/cpp/bindings/call_internal.h deleted file mode 100644 index ddefd8eb28a..00000000000 --- a/chromium/mojo/public/cpp/bindings/call_internal.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 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 MOJO_PUBLIC_CPP_BINDINGS_CALL_INTERNAL_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_CALL_INTERNAL_H_ - -#include <utility> - -#include "base/component_export.h" -#include "base/macros.h" - -namespace mojo { -namespace internal { - -// Base class for temporary objects returned by |Remote<T>::rpc()|. This -// provides pass-through access to the passed calling proxy. -class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) CallProxyWrapperBase { - public: - explicit CallProxyWrapperBase(void* proxy); - CallProxyWrapperBase(CallProxyWrapperBase&& other); - ~CallProxyWrapperBase(); - - void* proxy() const { return proxy_; } - - private: - void* proxy_; - - DISALLOW_COPY_AND_ASSIGN(CallProxyWrapperBase); -}; - -template <typename T> -class CallProxyWrapper : public CallProxyWrapperBase { - public: - explicit CallProxyWrapper(T* proxy) : CallProxyWrapperBase(proxy) {} - CallProxyWrapper(CallProxyWrapper&& other) - : CallProxyWrapperBase(std::move(other)) {} - - T* operator->() const { return static_cast<T*>(proxy()); } - - private: - DISALLOW_COPY_AND_ASSIGN(CallProxyWrapper); -}; - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_CALL_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h b/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h index 498308a3108..79b334d34d8 100644 --- a/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h @@ -123,7 +123,7 @@ struct Serializer<InterfacePtrDataView<Base>, PendingRemote<T>> { static void Serialize(PendingRemote<T>& input, Interface_Data* output, SerializationContext* context) { - context->AddInterfaceInfo(input.TakePipe(), input.version(), output); + context->AddInterfaceInfo(input.PassPipe(), input.version(), output); } static bool Deserialize(Interface_Data* input, @@ -162,7 +162,7 @@ struct Serializer<InterfaceRequestDataView<Base>, PendingReceiver<T>> { static void Serialize(PendingReceiver<T>& input, Handle_Data* output, SerializationContext* context) { - context->AddHandle(ScopedHandle::From(input.TakePipe()), output); + context->AddHandle(ScopedHandle::From(input.PassPipe()), output); } static bool Deserialize(Handle_Data* input, diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_util.h b/chromium/mojo/public/cpp/bindings/lib/serialization_util.h index a7a99b3bb72..51eb5f230ba 100644 --- a/chromium/mojo/public/cpp/bindings/lib/serialization_util.h +++ b/chromium/mojo/public/cpp/bindings/lib/serialization_util.h @@ -77,62 +77,6 @@ bool CallSetToNullIfExists(UserType* output) { return false; } -template <typename T> -struct HasSetUpContextMethod { - template <typename U> - static char Test(decltype(U::SetUpContext) *); - template <typename U> - static int Test(...); - static const bool value = sizeof(Test<T>(0)) == sizeof(char); - - private: - EnsureTypeIsComplete<T> check_t_; -}; - -template <typename Traits, - bool has_context = HasSetUpContextMethod<Traits>::value> -struct CustomContextHelper; - -template <typename Traits> -struct CustomContextHelper<Traits, true> { - template <typename MaybeConstUserType> - static void* SetUp(MaybeConstUserType& input, SerializationContext* context) { - return Traits::SetUpContext(input); - } - - template <typename MaybeConstUserType> - static void TearDown(MaybeConstUserType& input, void* custom_context) { - Traits::TearDownContext(input, custom_context); - } -}; - -template <typename Traits> -struct CustomContextHelper<Traits, false> { - template <typename MaybeConstUserType> - static void* SetUp(MaybeConstUserType& input, SerializationContext* context) { - return nullptr; - } - - template <typename MaybeConstUserType> - static void TearDown(MaybeConstUserType& input, void* custom_context) { - DCHECK(!custom_context); - } -}; - -template <typename ReturnType, typename ParamType, typename InputUserType> -ReturnType CallWithContext(ReturnType (*f)(ParamType, void*), - InputUserType&& input, - void* context) { - return f(std::forward<InputUserType>(input), context); -} - -template <typename ReturnType, typename ParamType, typename InputUserType> -ReturnType CallWithContext(ReturnType (*f)(ParamType), - InputUserType&& input, - void* context) { - return f(std::forward<InputUserType>(input)); -} - template <typename T, typename MaybeConstUserType> struct HasGetBeginMethod { template <typename U> diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h index 1fe6b87af70..d11a0c74eee 100644 --- a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h @@ -29,12 +29,9 @@ struct Serializer<StringDataView, MaybeConstUserType> { if (CallIsNullIfExists<Traits>(input)) return; - void* custom_context = CustomContextHelper<Traits>::SetUp(input, context); - const size_t size = CallWithContext(Traits::GetSize, input, custom_context); - writer->Allocate(size, buffer); - memcpy((*writer)->storage(), - CallWithContext(Traits::GetData, input, custom_context), size); - CustomContextHelper<Traits>::TearDown(input, custom_context); + auto r = Traits::GetUTF8(input); + writer->Allocate(r.size(), buffer); + memcpy((*writer)->storage(), r.data(), r.size()); } static bool Deserialize(String_Data* input, diff --git a/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc b/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc index 71b758c49c1..540a154fd3f 100644 --- a/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc +++ b/chromium/mojo/public/cpp/bindings/lib/string_traits_wtf.cc @@ -4,43 +4,9 @@ #include "mojo/public/cpp/bindings/string_traits_wtf.h" -#include <string.h> - -#include "base/logging.h" -#include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/string_data_view.h" -#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" namespace mojo { -namespace { - -struct UTF8AdaptorInfo { - explicit UTF8AdaptorInfo(const WTF::String& input) : utf8_adaptor(input) { -#if DCHECK_IS_ON() - original_size_in_bytes = input.CharactersSizeInBytes(); -#endif - } - - ~UTF8AdaptorInfo() {} - - WTF::StringUTF8Adaptor utf8_adaptor; - -#if DCHECK_IS_ON() - // For sanity check only. - size_t original_size_in_bytes; -#endif -}; - -UTF8AdaptorInfo* ToAdaptor(const WTF::String& input, void* context) { - UTF8AdaptorInfo* adaptor = static_cast<UTF8AdaptorInfo*>(context); - -#if DCHECK_IS_ON() - DCHECK_EQ(adaptor->original_size_in_bytes, input.CharactersSizeInBytes()); -#endif - return adaptor; -} - -} // namespace // static void StringTraits<WTF::String>::SetToNull(WTF::String* output) { @@ -52,26 +18,9 @@ void StringTraits<WTF::String>::SetToNull(WTF::String* output) { } // static -void* StringTraits<WTF::String>::SetUpContext(const WTF::String& input) { - return new UTF8AdaptorInfo(input); -} - -// static -void StringTraits<WTF::String>::TearDownContext(const WTF::String& input, - void* context) { - delete ToAdaptor(input, context); -} - -// static -size_t StringTraits<WTF::String>::GetSize(const WTF::String& input, - void* context) { - return ToAdaptor(input, context)->utf8_adaptor.length(); -} - -// static -const char* StringTraits<WTF::String>::GetData(const WTF::String& input, - void* context) { - return ToAdaptor(input, context)->utf8_adaptor.Data(); +WTF::StringUTF8Adaptor StringTraits<WTF::String>::GetUTF8( + const WTF::String& input) { + return WTF::StringUTF8Adaptor(input); } // static diff --git a/chromium/mojo/public/cpp/bindings/pending_receiver.h b/chromium/mojo/public/cpp/bindings/pending_receiver.h index 342d077ab21..73d0ed5a5e3 100644 --- a/chromium/mojo/public/cpp/bindings/pending_receiver.h +++ b/chromium/mojo/public/cpp/bindings/pending_receiver.h @@ -8,6 +8,7 @@ #include <utility> #include "base/macros.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { @@ -34,12 +35,18 @@ class PendingReceiver { // any Remote and cannot be used to bind a Receiver. // // A valid PendingReceiver is commonly obtained by calling - // |Remote::BindNewReceiver()| on an existing unbound Remote instance or less - // commonly by calling calling |PendingRemote::MakeReceiver()| on an existing - // but invalid PendingRemote instance. + // |Remote::BindNewPipeAndPassReceiver()| on an existing unbound Remote + // instance or less commonly by calling calling + // |PendingRemote::InitWithNewPipeAndPassReceiver()| on an existing but + // invalid PendingRemote instance. PendingReceiver() = default; PendingReceiver(PendingReceiver&&) noexcept = default; + // Temporary implicit move constructor to aid in converting from use of + // InterfaceRequest<Interface> to PendingReceiver. + PendingReceiver(InterfaceRequest<Interface>&& request) + : PendingReceiver(request.PassMessagePipe()) {} + // Constructs a valid PendingReceiver from a valid raw message pipe handle. explicit PendingReceiver(ScopedMessagePipeHandle pipe) : pipe_(std::move(pipe)) { @@ -50,6 +57,12 @@ class PendingReceiver { PendingReceiver& operator=(PendingReceiver&&) noexcept = default; + // Temporary implicit conversion operator to InterfaceRequest<Interface> to + // aid in converting usage to PendingReceiver. + operator InterfaceRequest<Interface>() { + return InterfaceRequest<Interface>(PassPipe()); + } + // Indicates whether the PendingReceiver is valid, meaning it can ne used to // bind a Receiver that wants to begin dispatching method calls made by the // entangled Remote. @@ -61,10 +74,10 @@ class PendingReceiver { // effectively be dropped. void reset() { pipe_.reset(); } - // Takes ownership of this PendingReceiver's message pipe handle. After this + // Passes ownership of this PendingReceiver's message pipe handle. After this // call, the PendingReceiver is no longer in a valid state and can no longer // be used to bind a Receiver. - ScopedMessagePipeHandle TakePipe() WARN_UNUSED_RESULT { + ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT { return std::move(pipe_); } diff --git a/chromium/mojo/public/cpp/bindings/pending_remote.h b/chromium/mojo/public/cpp/bindings/pending_remote.h index cf37734e61b..ebac0a45214 100644 --- a/chromium/mojo/public/cpp/bindings/pending_remote.h +++ b/chromium/mojo/public/cpp/bindings/pending_remote.h @@ -38,11 +38,12 @@ class PendingRemote { // receiver and cannot be used to bind a Remote. // // A valid PendingRemote is typically obtained by calling - // |Receiver::BindNewRemote()| on an existing unbound Receiver instance. + // |Receiver::BindNewPipeAndPassRemote()| on an existing unbound Receiver + // instance. // // To simultaneously create a valid PendingRemote and an entangled // PendingReceiver for rarer cases where both objects need to be passed - // elsewhere, use the |MakeReceiver()| method defined below. + // elsewhere, use the |InitWithNewPipeAndPassReceiver()| method defined below. PendingRemote() = default; PendingRemote(PendingRemote&&) noexcept = default; @@ -73,7 +74,7 @@ class PendingRemote { // Takes ownership of this PendingRemote's message pipe handle. After this // call, the PendingRemote is no longer in a valid state and can no longer be // used to bind a Remote. - ScopedMessagePipeHandle TakePipe() WARN_UNUSED_RESULT { + ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT { version_ = 0; return std::move(pipe_); } @@ -83,9 +84,11 @@ class PendingRemote { // always zero. uint32_t version() const { return version_; } - // Creates a new PendingReceiver and entangles this PendingRemote with it. - // May only be called on an invalid PendingRemote. - PendingReceiver<Interface> MakeReceiver() WARN_UNUSED_RESULT { + // Creates a new message pipe, retaining one end in the PendingRemote (making + // it valid) and returning the other end as its entangled PendingReceiver. May + // only be called on an invalid PendingRemote. + PendingReceiver<Interface> InitWithNewPipeAndPassReceiver() + WARN_UNUSED_RESULT { DCHECK(!is_valid()) << "PendingRemote already has a receiver"; MessagePipe pipe; pipe_ = std::move(pipe.handle0); diff --git a/chromium/mojo/public/cpp/bindings/receiver.h b/chromium/mojo/public/cpp/bindings/receiver.h index e97d0aafa02..078a5ce8160 100644 --- a/chromium/mojo/public/cpp/bindings/receiver.h +++ b/chromium/mojo/public/cpp/bindings/receiver.h @@ -5,6 +5,7 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_H_ #define MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_H_ +#include <memory> #include <utility> #include "base/compiler_specific.h" @@ -25,8 +26,8 @@ namespace mojo { // implementation of Interface. Every Receiver object is permanently linked to // an implementation of Interface at construction time. The Receiver begins // receiving and scheduling method calls to the implementation once it becomes -// bound by consuming a PendingReceiver, either at construction time or by -// calling |Bind()|. +// bound either by consuming a PendingReceiver (at construction time or via +// |Bind()|) or by calling |BindNewPipeAndPassRemote()|. // // Receiver is NOT thread- or sequence- safe and must be used from a single // (but otherwise arbitrary) sequence. All bound Receiver objects are associated @@ -49,8 +50,8 @@ class Receiver { // Constructs an unbound Receiver linked to |impl| for the duration of the // Receive's lifetime. The Receiver can be bound later by calling |Bind()| or - // |BindNewRemote()|. An unbound Receiver does not schedule any asynchronous - // tasks. + // |BindNewPipeAndPassRemote()|. An unbound Receiver does not schedule any + // asynchronous tasks. explicit Receiver(ImplPointerType impl) : internal_state_(std::move(impl)) {} // Constructs a bound Receiver by consuming |pending_receiver|. The Receiver @@ -104,19 +105,19 @@ class Receiver { // notifications on the default SequencedTaskRunner (i.e. // base::SequencedTaskRunnerHandle::Get() at the time of this call). Must only // be called on an unbound Receiver. - PendingRemote<Interface> BindNewRemote() WARN_UNUSED_RESULT { - return BindNewRemote(nullptr); + PendingRemote<Interface> BindNewPipeAndPassRemote() WARN_UNUSED_RESULT { + return BindNewPipeAndPassRemote(nullptr); } // Like above, but the Receiver will schedule incoming |impl| method calls and // disconnection notifications on |task_runner| rather than on the default // SequencedTaskRunner. Must only be called on an unbound Receiver. // |task_runner| must run tasks on the same sequence that owns this Receiver. - PendingRemote<Interface> BindNewRemote( + PendingRemote<Interface> BindNewPipeAndPassRemote( scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT { DCHECK(!is_bound()) << "Receiver is already bound"; PendingRemote<Interface> remote; - Bind(remote.MakeReceiver(), std::move(task_runner)); + Bind(remote.InitWithNewPipeAndPassReceiver(), std::move(task_runner)); return remote; } @@ -138,7 +139,7 @@ class Receiver { // Receiver. void Bind(PendingReceiver<Interface> pending_receiver, scoped_refptr<base::SequencedTaskRunner> task_runner) { - internal_state_.Bind(pending_receiver.TakePipe(), std::move(task_runner)); + internal_state_.Bind(pending_receiver.PassPipe(), std::move(task_runner)); } // Unbinds this Receiver, preventing any further |impl| method calls or @@ -161,6 +162,14 @@ class Receiver { internal_state_.Unbind().PassMessagePipe()); } + // Adds a message filter to be notified of each incoming message before + // dispatch. If a filter returns |false| from Accept(), the message is not + // dispatched and the pipe is closed. Filters cannot be removed once added. + void AddFilter(std::unique_ptr<MessageReceiver> filter) { + DCHECK(is_bound()); + internal_state_.AddFilter(std::move(filter)); + } + private: internal::BindingState<Interface, ImplRefTraits> internal_state_; diff --git a/chromium/mojo/public/cpp/bindings/receiver_set.h b/chromium/mojo/public/cpp/bindings/receiver_set.h new file mode 100644 index 00000000000..59267047556 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/receiver_set.h @@ -0,0 +1,334 @@ +// Copyright 2019 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 MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_SET_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_SET_H_ + +#include <map> +#include <memory> +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "mojo/public/cpp/bindings/connection_error_callback.h" +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h" + +namespace mojo { + +using ReceiverId = size_t; + +template <typename ReceiverType> +struct ReceiverSetTraits; + +template <typename Interface, typename ImplRefTraits> +struct ReceiverSetTraits<Receiver<Interface, ImplRefTraits>> { + using InterfaceType = Interface; + using ImplPointerType = typename ImplRefTraits::PointerType; +}; + +template <typename ContextType> +struct ReceiverSetContextTraits { + using Type = ContextType; + + static constexpr bool SupportsContext() { return true; } +}; + +template <> +struct ReceiverSetContextTraits<void> { + // NOTE: This choice of Type only matters insofar as it affects the size of + // the |context_| field of a ReceiverSetBase::Entry with void context. The + // context value is never used in this case. + using Type = bool; + + static constexpr bool SupportsContext() { return false; } +}; + +// Generic helper used to own a collection of Receiver endpoints. For +// convenience this type automatically manages cleanup of receivers that have +// been disconnected from their remote caller. +// +// Note that this type is not typically used directly by application. Instead, +// prefer to use one of the various aliases (like ReceiverSet) that are based on +// it. +// +// If |ContextType| is non-void, then every added receiver must include a +// context value of that type (when calling |Add()|), and |current_context()| +// will return that value during the extent of any message dispatch or +// disconnection notification pertaining to that specific receiver. +// +// So for example if ContextType is |int| and we call: +// +// Remote<mojom::Foo> foo1, foo2; +// ReceiverSet<mojom::Foo> receivers; +// // Assume |this| is an implementation of mojom::Foo... +// receivers.Add(this, foo1.BindNewReceiver(), 42); +// receivers.Add(this, foo2.BindNewReceiver(), 43); +// +// foo1->DoSomething(); +// foo2->DoSomething(); +// +// We can expect two asynchronous calls to |this->DoSomething()|. If that +// method looks at the value of |current_context()|, it will see a value of 42 +// while executing the call from |foo1| and a value of 43 while executing the +// call from |foo2|. +// +// Finally, note that ContextType can be any type of thing, including move-only +// objects like std::unique_ptrs. +template <typename ReceiverType, typename ContextType> +class ReceiverSetBase { + public: + using Traits = ReceiverSetTraits<ReceiverType>; + using Interface = typename Traits::InterfaceType; + using ImplPointerType = typename Traits::ImplPointerType; + using ContextTraits = ReceiverSetContextTraits<ContextType>; + using Context = typename ContextTraits::Type; + using PreDispatchCallback = base::RepeatingCallback<void(const Context&)>; + + ReceiverSetBase() : weak_ptr_factory_(this) {} + + // Sets a callback to be invoked any time a receiver in the set is + // disconnected. The callback is invoked *after* the receiver in question + // is removed from the set, and |current_context()| will correspond to the + // disconnected receiver's context value during the callback if the + // ContextType is not void. + void set_disconnect_handler(base::RepeatingClosure handler) { + disconnect_handler_ = std::move(handler); + } + + // Adds a new receiver to the set, binding |receiver| to |impl| with no + // additional context. If |task_runner| is non-null, the receiver's messages + // will be dispatched to |impl| on that |task_runner|. |task_runner| must run + // messages on the same sequence that owns this ReceiverSetBase. If + // |task_runner| is null, the value of + // |base::SequencedTaskRunnerHandle::Get()| at the time of the |Add()| call + // will be used to run scheduled tasks for the receiver. + ReceiverId Add( + ImplPointerType impl, + PendingReceiver<Interface> receiver, + scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) { + static_assert(!ContextTraits::SupportsContext(), + "Context value required for non-void context type."); + return AddImpl(std::move(impl), std::move(receiver), false, + std::move(task_runner)); + } + + // Adds a new receiver associated with |context|. See above method for all + // other (identical) details. + ReceiverId Add( + ImplPointerType impl, + PendingReceiver<Interface> receiver, + Context context, + scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) { + static_assert(ContextTraits::SupportsContext(), + "Context value unsupported for void context type."); + return AddImpl(std::move(impl), std::move(receiver), std::move(context), + std::move(task_runner)); + } + + // Removes a receiver from the set. Note that this is safe to call even if the + // receiver corresponding to |id| has already been removed (will be a no-op). + // + // Returns |true| if the receiver was removed and |false| if it didn't exist. + // + // A removed receiver is effectively closed and its remote (if any) will be + // disconnected. No further messages or disconnection notifications will be + // scheduled or executed for the removed receiver. + bool Remove(ReceiverId id) { + auto it = receivers_.find(id); + if (it == receivers_.end()) + return false; + receivers_.erase(it); + return true; + } + + // Removes all receivers from the set, effectively closing all of them. This + // ReceiverSet will not schedule or execute any further method invocations or + // disconnection notifications until a new receiver is added to the set. + void Clear() { receivers_.clear(); } + + bool empty() const { return receivers_.empty(); } + + size_t size() const { return receivers_.size(); } + + // Implementations may call this when processing a received method call or + // disconnection notification. During the extent of method invocation or + // disconnection notification, this returns the context value associated with + // the specific receiver which received the method call or disconnection. + // + // Each receiver must be associated with a context value when it's added + // to the set by |Add()|, and this is only supported when ContextType is + // not void. + // + // NOTE: It is important to understand that this must only be called within + // the stack frame of an actual interface method invocation or disconnect + // notification scheduled by a receiver. It is a illegal to attempt to call + // this any other time (e.g., from another async task you post from within a + // message handler). + const Context& current_context() const { + static_assert(ContextTraits::SupportsContext(), + "current_context() requires non-void context type."); + DCHECK(current_context_); + return *current_context_; + } + + // Implementations may call this when processing a received method call or + // disconnection notification. See above note for constraints on usage. + // This returns the ReceiverId associated with the specific receiver which + // received the incoming method call or disconnection notification. + ReceiverId current_receiver() const { + DCHECK(current_context_); + return current_receiver_; + } + + // Reports the currently dispatching Message as bad and removes the receiver + // which received it. Note that this is only legal to call from directly + // within the stack frame of an incoming method call. If you need to do + // asynchronous work before you can determine the legitimacy of a message, use + // GetBadMessageCallback() and retain its result until you're ready to invoke + // or discard it. + void ReportBadMessage(const std::string& error) { + GetBadMessageCallback().Run(error); + } + + // Acquires a callback which may be run to report the currently dispatching + // Message as bad and remove the receiver which received it. Note that this + // this is only legal to call from directly within the stack frame of an + // incoming method call, but the returned callback may be called exactly once + // any time thereafter, as long as the ReceiverSetBase itself hasn't been + // destroyed yet. If the callback is invoked, it must be done from the same + // sequence which owns the ReceiverSetBase, and upon invocation it will report + // the corresponding message as bad. + ReportBadMessageCallback GetBadMessageCallback() { + DCHECK(current_context_); + return base::BindOnce( + [](ReportBadMessageCallback error_callback, + base::WeakPtr<ReceiverSetBase> receiver_set, ReceiverId receiver_id, + const std::string& error) { + std::move(error_callback).Run(error); + if (receiver_set) + receiver_set->RemoveBinding(receiver_id); + }, + mojo::GetBadMessageCallback(), weak_ptr_factory_.GetWeakPtr(), + current_receiver()); + } + + private: + friend class Entry; + + class Entry { + public: + Entry(ImplPointerType impl, + PendingReceiver<Interface> receiver, + ReceiverSetBase* receiver_set, + ReceiverId receiver_id, + Context context, + scoped_refptr<base::SequencedTaskRunner> task_runner) + : receiver_(std::move(impl), + std::move(receiver), + std::move(task_runner)), + receiver_set_(receiver_set), + receiver_id_(receiver_id), + context_(std::move(context)) { + receiver_.AddFilter(std::make_unique<DispatchFilter>(this)); + receiver_.set_disconnect_handler( + base::BindOnce(&Entry::OnDisconnect, base::Unretained(this))); + } + + private: + class DispatchFilter : public MessageReceiver { + public: + explicit DispatchFilter(Entry* entry) : entry_(entry) {} + ~DispatchFilter() override {} + + private: + // MessageReceiver: + bool Accept(Message* message) override { + entry_->WillDispatch(); + return true; + } + + Entry* entry_; + + DISALLOW_COPY_AND_ASSIGN(DispatchFilter); + }; + + void WillDispatch() { + receiver_set_->SetDispatchContext(&context_, receiver_id_); + } + + void OnDisconnect() { + WillDispatch(); + receiver_set_->OnDisconnect(receiver_id_); + } + + ReceiverType receiver_; + ReceiverSetBase* const receiver_set_; + const ReceiverId receiver_id_; + Context const context_; + + DISALLOW_COPY_AND_ASSIGN(Entry); + }; + + void SetDispatchContext(const Context* context, ReceiverId receiver_id) { + current_context_ = context; + current_receiver_ = receiver_id; + } + + ReceiverId AddImpl(ImplPointerType impl, + PendingReceiver<Interface> receiver, + Context context, + scoped_refptr<base::SequencedTaskRunner> task_runner) { + ReceiverId id = next_receiver_id_++; + DCHECK_GE(next_receiver_id_, 0u); + auto entry = + std::make_unique<Entry>(std::move(impl), std::move(receiver), this, id, + std::move(context), std::move(task_runner)); + receivers_.insert(std::make_pair(id, std::move(entry))); + return id; + } + + void OnDisconnect(ReceiverId id) { + auto it = receivers_.find(id); + DCHECK(it != receivers_.end()); + + // We keep the Entry alive throughout error dispatch. + std::unique_ptr<Entry> entry = std::move(it->second); + receivers_.erase(it); + + if (disconnect_handler_) + disconnect_handler_.Run(); + } + + base::RepeatingClosure disconnect_handler_; + ReceiverId next_receiver_id_ = 0; + std::map<ReceiverId, std::unique_ptr<Entry>> receivers_; + const Context* current_context_ = nullptr; + ReceiverId current_receiver_; + base::WeakPtrFactory<ReceiverSetBase> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ReceiverSetBase); +}; + +// Common helper for a set of Receivers which do not own their implementation. +template <typename Interface, typename ContextType = void> +using ReceiverSet = ReceiverSetBase<Receiver<Interface>, ContextType>; + +// Helper for a set of Receivers where each bound Receiver is tied to an owned +// implementation. The |Add()| method takes a std::unique_ptr<Interface> for +// each bound implementation. +template <typename Interface, typename ContextType = void> +using OwnedReceiverSet = + ReceiverSetBase<Receiver<Interface, UniquePtrImplRefTraits<Interface>>, + ContextType>; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_SET_H_ diff --git a/chromium/mojo/public/cpp/bindings/remote.h b/chromium/mojo/public/cpp/bindings/remote.h index eeb7d9334de..afda20605ac 100644 --- a/chromium/mojo/public/cpp/bindings/remote.h +++ b/chromium/mojo/public/cpp/bindings/remote.h @@ -10,12 +10,10 @@ #include "base/callback_forward.h" #include "base/compiler_specific.h" -#include "base/location.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/sequenced_task_runner.h" -#include "mojo/public/cpp/bindings/call_internal.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -35,13 +33,13 @@ namespace mojo { // response callbacks and disconnection notifications. // // The most common ways to bind a Remote are to consume to a PendingRemote -// received via some IPC, or to call |BindNewReceiver()| and send the returned -// PendingReceiver somewhere useful (i.e., to a remote Receiver who will consume -// it). For example: +// received via some IPC, or to call |BindNewPipeAndPassReceiver()| and send the +// returned PendingReceiver somewhere useful (i.e., to a remote Receiver who +// will consume it). For example: // // mojo::Remote<mojom::Widget> widget; -// widget_factory->CreateWidget(widget.BindNewReceiver()); -// widget.rpc(FROM_HERE)->Click(); +// widget_factory->CreateWidget(widget.BindNewPipeAndPassReceiver()); +// widget->Click(); // // IMPORTANT: There are some things to be aware of regarding Interface method // calls as they relate to Remote object lifetime: @@ -85,25 +83,8 @@ class Remote { ~Remote() = default; - // Issue a method call to the remote implementation of Interface. If the - // remote end is still a PendingReceiver, the call will be queued within that - // object. If the remote end is bound to a live Receiver, the call will - // eventually be dispatched in the order it was received. - // - // If the Remote is no longer connected because the receiver has been - // destroyed, the call will be dropped. - internal::CallProxyWrapper<Interface> rpc(const base::Location& from_here) { - internal_state_.SetNextCallLocation(from_here); - return internal::CallProxyWrapper<Interface>(internal_state_.instance()); - } - // Exposes access to callable Interface methods directed at this Remote's // receiver. Must only be called on a bound Remote. - // - // Direct use of this accessor is discouraged and callers should prefer to use - // |rpc()| instead when making remote calls. Using |rpc()| can provide - // useful call-site attribution in DCHECK-enabled builds and makes IPC call - // sites easier to grok. typename Interface::Proxy_* get() const { DCHECK(is_bound()) << "Cannot issue Interface method calls on an unbound Remote"; @@ -111,13 +92,10 @@ class Remote { } // Shorthand form of |get()|. See above. - // - // TODO(https://crbug.com/934883): Figure out whether to disallow use of this - // operator in certain environments. typename Interface::Proxy_* operator->() const { return get(); } // Indicates whether this Remote is bound and thus can issue Interface method - // calls via e.g. |rpc()|. + // calls via the above accessors. // // NOTE: The state of being "bound" should not be confused with the state of // being "connected" (see |is_connected()| below). A Remote is NEVER passively @@ -171,15 +149,15 @@ class Remote { // will schedule any response callbacks or disconnection notifications on the // default SequencedTaskRunner (i.e. base::SequencedTaskRunnerHandle::Get() at // the time of this call). Must only be called on an unbound Remote. - PendingReceiver<Interface> BindNewReceiver() WARN_UNUSED_RESULT { - return BindNewReceiver(nullptr); + PendingReceiver<Interface> BindNewPipeAndPassReceiver() WARN_UNUSED_RESULT { + return BindNewPipeAndPassReceiver(nullptr); } // Like above, but the Remote will schedule response callbacks and // disconnection notifications on |task_runner| instead of the default // SequencedTaskRunner. |task_runner| must run tasks on the same sequence that // owns this Remote. - PendingReceiver<Interface> BindNewReceiver( + PendingReceiver<Interface> BindNewPipeAndPassReceiver( scoped_refptr<base::SequencedTaskRunner> task_runner) WARN_UNUSED_RESULT { MessagePipe pipe; Bind(PendingRemote<Interface>(std::move(pipe.handle0), 0), @@ -204,7 +182,7 @@ class Remote { void Bind(PendingRemote<Interface> pending_remote, scoped_refptr<base::SequencedTaskRunner> task_runner) { DCHECK(!is_bound()) << "Remote is already bound"; - internal_state_.Bind(InterfacePtrInfo<Interface>(pending_remote.TakePipe(), + internal_state_.Bind(InterfacePtrInfo<Interface>(pending_remote.PassPipe(), pending_remote.version()), std::move(task_runner)); diff --git a/chromium/mojo/public/cpp/bindings/string_traits.h b/chromium/mojo/public/cpp/bindings/string_traits.h index 165c9fa8cd8..bd256472c5a 100644 --- a/chromium/mojo/public/cpp/bindings/string_traits.h +++ b/chromium/mojo/public/cpp/bindings/string_traits.h @@ -12,8 +12,7 @@ namespace mojo { // This must be specialized for any type |T| to be serialized/deserialized as // a mojom string. // -// Imagine you want to specialize it for CustomString, usually you need to -// implement: +// An example specialization for CustomString: // // template <T> // struct StringTraits<CustomString> { @@ -21,31 +20,14 @@ namespace mojo { // static bool IsNull(const CustomString& input); // static void SetToNull(CustomString* output); // -// static size_t GetSize(const CustomString& input); -// static const char* GetData(const CustomString& input); +// // This doesn't need to be a base::StringPiece; it simply needs to be a +// // type that exposes a data() method that returns a pointer to the UTF-8 +// // bytes and a size() method that returns the length of the UTF-8 bytes. +// static std::span<char> GetUTF8(const CustomString& input); // // // The caller guarantees that |!input.is_null()|. // static bool Read(StringDataView input, CustomString* output); // }; -// -// In some cases, you may need to do conversion before you can return the size -// and data as 8-bit characters for serialization. (For example, CustomString is -// UTF-16 string). In that case, you can add two optional methods: -// -// static void* SetUpContext(const CustomString& input); -// static void TearDownContext(const CustomString& input, void* context); -// -// And then you append a second parameter, void* context, to GetSize() and -// GetData(): -// -// static size_t GetSize(const CustomString& input, void* context); -// static const char* GetData(const CustomString& input, void* context); -// -// If a CustomString instance is not null, the serialization code will call -// SetUpContext() at the beginning, and pass the resulting context pointer to -// GetSize()/GetData(). After serialization is done, it calls TearDownContext() -// so that you can do any necessary cleanup. -// template <typename T> struct StringTraits { static_assert(internal::AlwaysFalse<T>::value, diff --git a/chromium/mojo/public/cpp/bindings/string_traits_stl.h b/chromium/mojo/public/cpp/bindings/string_traits_stl.h index f6cc8ad098f..cb3c5fb4a07 100644 --- a/chromium/mojo/public/cpp/bindings/string_traits_stl.h +++ b/chromium/mojo/public/cpp/bindings/string_traits_stl.h @@ -23,9 +23,7 @@ struct StringTraits<std::string> { output->clear(); } - static size_t GetSize(const std::string& input) { return input.size(); } - - static const char* GetData(const std::string& input) { return input.data(); } + static const std::string& GetUTF8(const std::string& input) { return input; } static bool Read(StringDataView input, std::string* output) { output->assign(input.storage(), input.size()); diff --git a/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h b/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h index af6be893ac0..785537962c9 100644 --- a/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h +++ b/chromium/mojo/public/cpp/bindings/string_traits_string_piece.h @@ -12,7 +12,7 @@ namespace mojo { template <> struct StringTraits<base::StringPiece> { - static bool IsNull(const base::StringPiece& input) { + static bool IsNull(base::StringPiece input) { // base::StringPiece is always converted to non-null mojom string. We could // have let StringPiece containing a null data pointer map to null mojom // string, but StringPiece::empty() returns true in this case. It seems @@ -26,11 +26,7 @@ struct StringTraits<base::StringPiece> { output->set(nullptr, 0); } - static size_t GetSize(const base::StringPiece& input) { return input.size(); } - - static const char* GetData(const base::StringPiece& input) { - return input.data(); - } + static base::StringPiece GetUTF8(base::StringPiece input) { return input; } static bool Read(StringDataView input, base::StringPiece* output) { output->set(input.storage(), input.size()); diff --git a/chromium/mojo/public/cpp/bindings/string_traits_wtf.h b/chromium/mojo/public/cpp/bindings/string_traits_wtf.h index 51601d1ab85..662fff5daf7 100644 --- a/chromium/mojo/public/cpp/bindings/string_traits_wtf.h +++ b/chromium/mojo/public/cpp/bindings/string_traits_wtf.h @@ -7,6 +7,7 @@ #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/string_traits.h" +#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace mojo { @@ -16,12 +17,7 @@ struct StringTraits<WTF::String> { static bool IsNull(const WTF::String& input) { return input.IsNull(); } static void SetToNull(WTF::String* output); - static void* SetUpContext(const WTF::String& input); - static void TearDownContext(const WTF::String& input, void* context); - - static size_t GetSize(const WTF::String& input, void* context); - - static const char* GetData(const WTF::String& input, void* context); + static WTF::StringUTF8Adaptor GetUTF8(const WTF::String& input); static bool Read(StringDataView input, WTF::String* output); }; diff --git a/chromium/mojo/public/cpp/platform/BUILD.gn b/chromium/mojo/public/cpp/platform/BUILD.gn index c20f95bb6d7..79c017608d8 100644 --- a/chromium/mojo/public/cpp/platform/BUILD.gn +++ b/chromium/mojo/public/cpp/platform/BUILD.gn @@ -38,6 +38,10 @@ component("platform") { sources += [ "named_platform_channel_posix.cc" ] } + if (is_mac) { + sources += [ "named_platform_channel_mac.cc" ] + } + if (is_fuchsia) { public_deps += [ "//third_party/fuchsia-sdk/sdk:fdio", diff --git a/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc b/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc new file mode 100644 index 00000000000..0a2df95360d --- /dev/null +++ b/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc @@ -0,0 +1,83 @@ +// Copyright 2019 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 "mojo/public/cpp/platform/named_platform_channel.h" + +#include <mach/port.h> +#include <servers/bootstrap.h> + +#include "base/mac/foundation_util.h" +#include "base/mac/mach_logging.h" +#include "base/mac/scoped_mach_port.h" +#include "base/rand_util.h" +#include "base/strings/stringprintf.h" +#include "mojo/public/cpp/platform/platform_channel.h" + +namespace mojo { + +namespace { + +std::string GetBootstrapName(const std::string& name) { + if (name.empty()) { + return base::StringPrintf("%s.mojo.%llu", base::mac::BaseBundleID(), + base::RandUint64()); + } + return name; +} + +} // namespace + +// TODO(crbug.com/932175): This namespace will go away and these methods +// will be defined direclty on NamedPlatformChannel. +namespace NamedPlatformChannelMac { + +// static +COMPONENT_EXPORT(MOJO_CPP_PLATFORM) +PlatformChannelServerEndpoint CreateServerEndpoint( + const NamedPlatformChannel::Options& options, + NamedPlatformChannel::ServerName* server_name) { + const std::string bootstrap_name = GetBootstrapName(options.server_name); + DCHECK_LT(bootstrap_name.length(), + static_cast<size_t>(BOOTSTRAP_MAX_NAME_LEN)); + + base::mac::ScopedMachReceiveRight receive_right; + kern_return_t kr = bootstrap_check_in( + bootstrap_port, bootstrap_name.c_str(), + base::mac::ScopedMachReceiveRight::Receiver(receive_right).get()); + if (kr != KERN_SUCCESS) { + BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in " << bootstrap_name; + return PlatformChannelServerEndpoint(); + } + + // The mpl_qlimit specified here should stay in sync with PlatformChannel. + mach_port_limits_t limits{}; + limits.mpl_qlimit = MACH_PORT_QLIMIT_LARGE; + kr = mach_port_set_attributes( + mach_task_self(), receive_right.get(), MACH_PORT_LIMITS_INFO, + reinterpret_cast<mach_port_info_t>(&limits), MACH_PORT_LIMITS_INFO_COUNT); + MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_set_attributes"; + + *server_name = bootstrap_name; + return PlatformChannelServerEndpoint( + PlatformHandle(std::move(receive_right))); +} + +// static +COMPONENT_EXPORT(MOJO_CPP_PLATFORM) +PlatformChannelEndpoint CreateClientEndpoint( + const NamedPlatformChannel::ServerName& server_name) { + base::mac::ScopedMachSendRight send_right; + kern_return_t kr = bootstrap_look_up( + bootstrap_port, server_name.c_str(), + base::mac::ScopedMachSendRight::Receiver(send_right).get()); + if (kr != KERN_SUCCESS) { + BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up " << server_name; + return PlatformChannelEndpoint(); + } + + return PlatformChannelEndpoint(PlatformHandle(std::move(send_right))); +} + +} // namespace NamedPlatformChannelMac +} // namespace mojo diff --git a/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc b/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc index 9082ac4da59..d5f82d86430 100644 --- a/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc +++ b/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc @@ -15,6 +15,8 @@ #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "build/build_config.h" +#include "mojo/public/cpp/platform/features.h" namespace mojo { @@ -77,10 +79,26 @@ PlatformHandle CreateUnixDomainSocket() { } // namespace +#if defined(OS_MACOSX) && !defined(OS_IOS) +// Temporarily forward declare named_platform_channel_mac.cc symbols. +namespace NamedPlatformChannelMac { +PlatformChannelServerEndpoint CreateServerEndpoint( + const NamedPlatformChannel::Options& options, + NamedPlatformChannel::ServerName* server_name); +PlatformChannelEndpoint CreateClientEndpoint( + const NamedPlatformChannel::ServerName& server_name); +} // namespace NamedPlatformChannelMac +#endif + // static PlatformChannelServerEndpoint NamedPlatformChannel::CreateServerEndpoint( const Options& options, ServerName* server_name) { +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + return NamedPlatformChannelMac::CreateServerEndpoint(options, server_name); + } +#endif ServerName name = options.server_name; if (name.empty()) name = GenerateRandomServerName(options); @@ -128,6 +146,11 @@ PlatformChannelServerEndpoint NamedPlatformChannel::CreateServerEndpoint( // static PlatformChannelEndpoint NamedPlatformChannel::CreateClientEndpoint( const ServerName& server_name) { +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + return NamedPlatformChannelMac::CreateClientEndpoint(server_name); + } +#endif DCHECK(!server_name.empty()); struct sockaddr_un unix_addr; diff --git a/chromium/mojo/public/cpp/platform/platform_channel.cc b/chromium/mojo/public/cpp/platform/platform_channel.cc index fd73f967da4..8502ae35c95 100644 --- a/chromium/mojo/public/cpp/platform/platform_channel.cc +++ b/chromium/mojo/public/cpp/platform/platform_channel.cc @@ -7,6 +7,7 @@ #include <cstddef> #include <cstdint> #include <string> +#include <utility> #include "base/logging.h" #include "base/rand_util.h" @@ -15,6 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "mojo/public/cpp/platform/features.h" #if defined(OS_WIN) #include <windows.h> @@ -35,6 +37,13 @@ #include "base/posix/global_descriptors.h" #endif +#if defined(OS_MACOSX) && !defined(OS_IOS) +#include <mach/port.h> + +#include "base/mac/mach_logging.h" +#include "base/mac/scoped_mach_port.h" +#endif + #if defined(OS_POSIX) && !defined(OS_NACL_SFI) #include <sys/socket.h> #elif defined(OS_NACL_SFI) @@ -95,6 +104,28 @@ void CreateChannel(PlatformHandle* local_endpoint, } #elif defined(OS_POSIX) +#if defined(OS_MACOSX) && !defined(OS_IOS) +// TODO(crbug.com/932175): This will be renamed CreateChannel(). +void CreateMachChannel(PlatformHandle* local_endpoint, + PlatformHandle* remote_endpoint) { + // Mach messaging is simplex; and in order to enable full-duplex + // communication, the Mojo channel implementation performs an internal + // handshake with its peer to establish two sets of Mach receive and send + // rights. The handshake process starts with the creation of one + // PlatformChannel endpoint. + base::mac::ScopedMachReceiveRight receive; + base::mac::ScopedMachSendRight send; + // The mpl_qlimit specified here should stay in sync with + // NamedPlatformChannel. + CHECK(base::mac::CreateMachPort(&receive, &send, MACH_PORT_QLIMIT_LARGE)); + + // In a reverse of Mach messaging semantics, in Mojo the "local" endpoint is + // the send right, while the "remote" end is the receive right. + *local_endpoint = PlatformHandle(std::move(send)); + *remote_endpoint = PlatformHandle(std::move(receive)); +} +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + #if defined(OS_ANDROID) // Leave room for any other descriptors defined in content for example. // TODO(https://crbug.com/676442): Consider changing base::GlobalDescriptors to @@ -114,6 +145,11 @@ bool IsTargetDescriptorUsed(const base::FileHandleMappingVector& mapping, void CreateChannel(PlatformHandle* local_endpoint, PlatformHandle* remote_endpoint) { +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + return CreateMachChannel(local_endpoint, remote_endpoint); + } +#endif int fds[2]; #if defined(OS_NACL_SFI) PCHECK(imc_socketpair(fds) == 0); @@ -163,9 +199,12 @@ PlatformChannel::~PlatformChannel() = default; PlatformChannel& PlatformChannel::operator=(PlatformChannel&& other) = default; -void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info, +void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info_input, std::string* value) { +#if !defined(OS_MACOSX) || defined(OS_IOS) + auto* info = info_input; DCHECK(info); +#endif DCHECK(value); DCHECK(remote_endpoint_.is_valid()); @@ -183,6 +222,26 @@ void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info, info->emplace_back(fd, mapped_fd); *value = base::NumberToString(mapped_fd); #elif defined(OS_POSIX) +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + auto* info = static_cast<base::MachPortsForRendezvous*>(info_input); + DCHECK(remote_endpoint_.platform_handle().is_mach_receive()); + base::mac::ScopedMachReceiveRight receive_right = + remote_endpoint_.TakePlatformHandle().TakeMachReceiveRight(); + base::MachPortsForRendezvous::key_type rendezvous_key = 0; + do { + rendezvous_key = + static_cast<decltype(rendezvous_key)>(base::RandUint64()); + } while (info->find(rendezvous_key) != info->end()); + auto it = info->insert(std::make_pair( + rendezvous_key, base::MachRendezvousPort(std::move(receive_right)))); + DCHECK(it.second) << "Failed to insert port for rendezvous."; + *value = base::NumberToString(rendezvous_key); + return; + } + + auto* info = static_cast<base::FileHandleMappingVector*>(info_input); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) // Arbitrary sanity check to ensure the loop below terminates reasonably // quickly. CHECK_LT(info->size(), 1000u); @@ -215,6 +274,19 @@ void PlatformChannel::PrepareToPassRemoteEndpoint( PrepareToPassRemoteEndpoint(&options->handles_to_inherit, command_line); #elif defined(OS_FUCHSIA) PrepareToPassRemoteEndpoint(&options->handles_to_transfer, command_line); +#elif defined(OS_MACOSX) && !defined(OS_IOS) + HandlePassingInfo info; + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) + info = options->mach_ports_for_rendezvous; + else + info = options->fds_to_remap; + + PrepareToPassRemoteEndpoint(&info, command_line); + + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) + options->mach_ports_for_rendezvous = info; + else + options->fds_to_remap = info; #elif defined(OS_POSIX) PrepareToPassRemoteEndpoint(&options->fds_to_remap, command_line); #else @@ -262,6 +334,26 @@ PlatformChannelEndpoint PlatformChannel::RecoverPassedEndpointFromString( return PlatformChannelEndpoint(PlatformHandle( base::ScopedFD(base::GlobalDescriptors::GetInstance()->Get(key)))); #elif defined(OS_POSIX) +#if defined(OS_MACOSX) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) { + auto* client = base::MachPortRendezvousClient::GetInstance(); + if (!client) { + DLOG(ERROR) << "Mach rendezvous failed."; + return PlatformChannelEndpoint(); + } + uint32_t rendezvous_key = 0; + if (value.empty() || !base::StringToUint(value, &rendezvous_key)) { + DLOG(ERROR) << "Invalid PlatformChannel rendezvous key."; + return PlatformChannelEndpoint(); + } + auto receive = client->TakeReceiveRight(rendezvous_key); + if (!receive.is_valid()) { + DLOG(ERROR) << "Invalid PlatformChannel receive right."; + return PlatformChannelEndpoint(); + } + return PlatformChannelEndpoint(PlatformHandle(std::move(receive))); + } +#endif // defined(OS_MACOSX) && !defined(OS_IOS) int fd = -1; if (value.empty() || !base::StringToInt(value, &fd) || fd < base::GlobalDescriptors::kBaseDescriptor) { diff --git a/chromium/mojo/public/cpp/platform/platform_channel.h b/chromium/mojo/public/cpp/platform/platform_channel.h index 534c6bbfdc2..d31668a3286 100644 --- a/chromium/mojo/public/cpp/platform/platform_channel.h +++ b/chromium/mojo/public/cpp/platform/platform_channel.h @@ -41,6 +41,18 @@ class COMPONENT_EXPORT(MOJO_CPP_PLATFORM) PlatformChannel { using HandlePassingInfo = base::HandlesToInheritVector; #elif defined(OS_FUCHSIA) using HandlePassingInfo = base::HandlesToTransferVector; +#elif defined(OS_MACOSX) && !defined(OS_IOS) + // This type represents a union between MachPortsForRendezvous and + // FileHandleMappingVector, so that the type to use can be determined at run- + // time. + // TODO(crbug.com/932175): This will become a typedef to + // base::MachPortsForRendezvous in the future. + class HandlePassingInfo : public base::MachPortsForRendezvous, + public base::FileHandleMappingVector { + public: + using base::MachPortsForRendezvous::operator=; + using base::FileHandleMappingVector::operator=; + }; #elif defined(OS_POSIX) using HandlePassingInfo = base::FileHandleMappingVector; #else diff --git a/chromium/mojo/public/cpp/system/buffer.h b/chromium/mojo/public/cpp/system/buffer.h index d816e6a79de..e20a8fe14d9 100644 --- a/chromium/mojo/public/cpp/system/buffer.h +++ b/chromium/mojo/public/cpp/system/buffer.h @@ -58,7 +58,7 @@ class MOJO_CPP_SYSTEM_EXPORT SharedBufferHandle : public Handle { // // Note for those converting legacy shared memory to the // base::*SharedMemoryRegion API: if SharedBufferHandle::Create is used for - // your shared memory regions, the mojo::Create*SahredMemoryRegion methods in + // your shared memory regions, the mojo::Create*SharedMemoryRegion methods in // mojo/public/cpp/base/shared_memory_utils.h should be used. These know how // to use a broker to create regions in unprivileged contexts in the same way // as this SharedBufferHandle::Create method. diff --git a/chromium/mojo/public/cpp/system/data_pipe.h b/chromium/mojo/public/cpp/system/data_pipe.h index 205af858aee..eb7d6e279ad 100644 --- a/chromium/mojo/public/cpp/system/data_pipe.h +++ b/chromium/mojo/public/cpp/system/data_pipe.h @@ -131,16 +131,12 @@ inline MojoResult CreateDataPipe( return rv; } -// A wrapper class that automatically creates a data pipe and owns both handles. +// DEPRECATED: use |CreateDataPipe| instead. // -// Note that this class is not safe to use in production code, as there is no -// way for it to report failure while creating the pipe, while in practice -// creating a new data pipe does fail every now and then. Instead just call -// CreateDataPipe directly and check its return value. +// This class is not safe to use in production code as there is no way for it to +// report failure while creating the pipe and it will CHECK in case of failures. // -// TODO(vtl): Make an even more friendly version? (Maybe templatized for a -// particular type instead of some "element"? Maybe functions that take -// vectors?) +// A wrapper class that automatically creates a data pipe and owns both handles. class MOJO_CPP_SYSTEM_EXPORT DataPipe { public: DataPipe(); diff --git a/chromium/mojo/public/cpp/system/platform_handle.cc b/chromium/mojo/public/cpp/system/platform_handle.cc index 9e55f550b2f..f00df808682 100644 --- a/chromium/mojo/public/cpp/system/platform_handle.cc +++ b/chromium/mojo/public/cpp/system/platform_handle.cc @@ -33,6 +33,8 @@ base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) { #endif } +} // namespace + ScopedSharedBufferHandle WrapPlatformSharedMemoryRegion( base::subtle::PlatformSharedMemoryRegion region) { if (!region.IsValid()) @@ -177,8 +179,6 @@ base::subtle::PlatformSharedMemoryRegion UnwrapPlatformSharedMemoryRegion( base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low)); } -} // namespace - ScopedHandle WrapPlatformHandle(PlatformHandle handle) { MojoPlatformHandle platform_handle; PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handle); diff --git a/chromium/mojo/public/cpp/system/platform_handle.h b/chromium/mojo/public/cpp/system/platform_handle.h index b18ceafacd9..5134275edc5 100644 --- a/chromium/mojo/public/cpp/system/platform_handle.h +++ b/chromium/mojo/public/cpp/system/platform_handle.h @@ -76,6 +76,14 @@ enum class UnwrappedSharedMemoryHandleProtection { kReadOnly, }; +// Wraps and unwraps base::subtle::PlatformSharedMemoryRegions. This should be +// used only while transitioning from the legacy shared memory API. In new code +// only base::*SharedMemoryRegion should be used instead. +ScopedSharedBufferHandle WrapPlatformSharedMemoryRegion( + base::subtle::PlatformSharedMemoryRegion region); +base::subtle::PlatformSharedMemoryRegion UnwrapPlatformSharedMemoryRegion( + ScopedSharedBufferHandle mojo_handle); + // Wraps a PlatformHandle from the C++ platform support library as a Mojo // handle. MOJO_CPP_SYSTEM_EXPORT ScopedHandle WrapPlatformHandle(PlatformHandle handle); diff --git a/chromium/mojo/public/cpp/test/BUILD.gn b/chromium/mojo/public/cpp/test/BUILD.gn new file mode 100644 index 00000000000..c667cd41bb4 --- /dev/null +++ b/chromium/mojo/public/cpp/test/BUILD.gn @@ -0,0 +1,12 @@ +# Copyright 2019 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("test_mojom") { + testonly = true + sources = [ + "module.test-mojom", + ] +} diff --git a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn index 1309315189b..a5efd42d93c 100644 --- a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn @@ -320,7 +320,7 @@ component("test_export_component") { if (!is_ios) { component("test_export_blink_component") { testonly = true - deps = [ + public_deps = [ ":test_export_blink", ] } diff --git a/chromium/mojo/public/java/system/BUILD.gn b/chromium/mojo/public/java/system/BUILD.gn index 0025f5588d3..49b2dbcaebf 100644 --- a/chromium/mojo/public/java/system/BUILD.gn +++ b/chromium/mojo/public/java/system/BUILD.gn @@ -174,4 +174,5 @@ instrumentation_test_apk("mojo_test_apk") { shared_libraries = [ ":mojo_java_unittests" ] apk_name = "MojoTest" android_manifest = "javatests/AndroidManifest.xml" + enable_multidex = false } diff --git a/chromium/mojo/public/js/BUILD.gn b/chromium/mojo/public/js/BUILD.gn index b27019dde25..3f94385c708 100644 --- a/chromium/mojo/public/js/BUILD.gn +++ b/chromium/mojo/public/js/BUILD.gn @@ -126,3 +126,9 @@ grit("resources") { "//mojo/public/mojom/base:base_js", ] } + +group("tests") { + deps = [ + "//mojo/public/js/test:compile_test", + ] +} diff --git a/chromium/mojo/public/js/bindings_lite.js b/chromium/mojo/public/js/bindings_lite.js index c7fd65834b2..e16d8db629d 100644 --- a/chromium/mojo/public/js/bindings_lite.js +++ b/chromium/mojo/public/js/bindings_lite.js @@ -84,7 +84,7 @@ mojo.internal.align = function(size, alignment) { */ mojo.internal.setInt64 = function(dataView, byteOffset, value) { if (mojo.internal.kHostLittleEndian) { - dataView.setInt32( + dataView.setUint32( byteOffset, Number(BigInt(value) & BigInt(0xffffffff)), mojo.internal.kHostLittleEndian); dataView.setInt32( @@ -94,7 +94,7 @@ mojo.internal.setInt64 = function(dataView, byteOffset, value) { dataView.setInt32( byteOffset, Number(BigInt(value) >> BigInt(32)), mojo.internal.kHostLittleEndian); - dataView.setInt32( + dataView.setUint32( byteOffset + 4, Number(BigInt(value) & BigInt(0xffffffff)), mojo.internal.kHostLittleEndian); } @@ -131,10 +131,10 @@ mojo.internal.setUint64 = function(dataView, byteOffset, value) { mojo.internal.getInt64 = function(dataView, byteOffset) { let low, high; if (mojo.internal.kHostLittleEndian) { - low = dataView.getInt32(byteOffset, mojo.internal.kHostLittleEndian); + low = dataView.getUint32(byteOffset, mojo.internal.kHostLittleEndian); high = dataView.getInt32(byteOffset + 4, mojo.internal.kHostLittleEndian); } else { - low = dataView.getInt32(byteOffset + 4, mojo.internal.kHostLittleEndian); + low = dataView.getUint32(byteOffset + 4, mojo.internal.kHostLittleEndian); high = dataView.getInt32(byteOffset, mojo.internal.kHostLittleEndian); } const value = (BigInt(high) << BigInt(32)) | BigInt(low); diff --git a/chromium/mojo/public/js/interface_support.js b/chromium/mojo/public/js/interface_support.js index 9e36eb1fbb0..77ab0f966c3 100644 --- a/chromium/mojo/public/js/interface_support.js +++ b/chromium/mojo/public/js/interface_support.js @@ -257,7 +257,7 @@ mojo.internal.interfaceSupport.InterfaceProxyBase = class { } // The pipe has already been closed, so just drop the message. - if (!this.reader_ || this.reader_.isStopped()) + if (responseStruct && (!this.reader_ || this.reader_.isStopped())) return Promise.reject(new Error('The pipe has already been closed.')); const requestId = this.nextRequestId_++; @@ -531,6 +531,10 @@ mojo.internal.interfaceSupport.InterfaceTarget = class { /** @private {mojo.internal.interfaceSupport.ControlMessageHandler} */ this.controlMessageHandler_ = null; + + /** @private {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */ + this.connectionErrorEventRouter_ = + new mojo.internal.interfaceSupport.ConnectionErrorEventRouter; } /** @@ -569,6 +573,14 @@ mojo.internal.interfaceSupport.InterfaceTarget = class { } /** + * @return {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} + * @export + */ + getConnectionErrorEventRouter() { + return this.connectionErrorEventRouter_; + } + + /** * @param {!MojoHandle} handle * @param {!ArrayBuffer} buffer * @param {!Array<MojoHandle>} handles @@ -634,6 +646,7 @@ mojo.internal.interfaceSupport.InterfaceTarget = class { const reader = this.readers_.get(handle); if (!reader) return; + this.connectionErrorEventRouter_.dispatchErrorEvent(); reader.stopAndCloseHandle(); this.readers_.delete(handle); } @@ -679,6 +692,8 @@ mojo.internal.interfaceSupport.HandleReader = class { } stopAndCloseHandle() { + if (!this.watcher_) + return; this.stop(); this.handle_.close(); } diff --git a/chromium/mojo/public/js/mojo_bindings_resources.grd b/chromium/mojo/public/js/mojo_bindings_resources.grd index deddde08110..eb615379ee5 100644 --- a/chromium/mojo/public/js/mojo_bindings_resources.grd +++ b/chromium/mojo/public/js/mojo_bindings_resources.grd @@ -13,11 +13,14 @@ <translations /> <release seq="1"> <includes> - <include name="IDR_MOJO_MOJO_BINDINGS_JS" - file="${root_gen_dir}/mojo/public/js/mojo_bindings.js" - use_base_dir="false" - type="BINDATA" - compress="gzip" /> + <!-- All resources included on Android should use the lite bindings. --> + <if expr="not is_android"> + <include name="IDR_MOJO_MOJO_BINDINGS_JS" + file="${root_gen_dir}/mojo/public/js/mojo_bindings.js" + use_base_dir="false" + type="BINDATA" + compress="gzip" /> + </if> <include name="IDR_MOJO_MOJO_BINDINGS_LITE_JS" file="${root_gen_dir}/mojo/public/js/mojo_bindings_lite.js" use_base_dir="false" diff --git a/chromium/mojo/public/js/test/BUILD.gn b/chromium/mojo/public/js/test/BUILD.gn new file mode 100644 index 00000000000..8816cc14c29 --- /dev/null +++ b/chromium/mojo/public/js/test/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2019 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. + +import("//mojo/public/tools/bindings/mojom.gni") +import("//third_party/closure_compiler/closure_args.gni") +import("//third_party/closure_compiler/compile_js.gni") + +mojom("test_mojom") { + testonly = true + sources = [ + "module_a.test-mojom", + "module_b_1.test-mojom", + "module_b_2.test-mojom", + ] +} + +if (enable_mojom_closure_compile || closure_compile) { + js_library("compile_test_sources") { + sources = [ + "compile_test.js", + ] + deps = [ + ":test_mojom_js_library_for_compile", + ] + } + + js_binary("compile_test") { + outputs = [ + "$target_gen_dir/compile_test.js", + ] + deps = [ + ":compile_test_sources", + ":test_mojom_js_library_for_compile", + ] + closure_flags = strict_error_checking_closure_args + [ + "compilation_level=ADVANCED_OPTIMIZATIONS", + "language_in=ECMASCRIPT_2017", + "language_out=ECMASCRIPT5_STRICT", + "generate_exports", + ] + } +} else { + group("compile_test") { + } +} diff --git a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 6cd039ea3c8..c2a0f444482 100644 --- a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni @@ -13,6 +13,7 @@ _typemap_imports = [ "//chromeos/components/multidevice/mojom/typemaps.gni", "//chromeos/services/secure_channel/public/mojom/typemaps.gni", "//components/arc/common/typemaps.gni", + "//components/chromeos_camera/common/typemaps.gni", "//components/sync/mojo/typemaps.gni", "//components/typemaps.gni", "//content/common/bluetooth/typemaps.gni", @@ -48,15 +49,16 @@ _typemap_imports = [ "//third_party/blink/common/typemaps.gni", "//third_party/blink/public/public_typemaps.gni", "//ui/accessibility/mojom/typemaps.gni", - "//ui/base/mojo/typemaps.gni", "//ui/base/accelerators/mojo/typemaps.gni", + "//ui/base/ime/mojo/typemaps.gni", + "//ui/base/mojo/typemaps.gni", "//ui/display/mojo/typemaps.gni", "//ui/events/devices/mojo/typemaps.gni", "//ui/events/mojo/typemaps.gni", "//ui/gfx/typemaps.gni", "//ui/latency/mojo/typemaps.gni", - "//ui/ozone/public/interfaces/typemaps.gni", "//ui/message_center/public/mojo/typemaps.gni", + "//ui/ozone/public/interfaces/typemaps.gni", "//url/mojom/typemaps.gni", ] diff --git a/chromium/mojo/public/tools/bindings/generate_type_mappings.py b/chromium/mojo/public/tools/bindings/generate_type_mappings.py index ee55e99404e..d6796afb8b3 100755 --- a/chromium/mojo/public/tools/bindings/generate_type_mappings.py +++ b/chromium/mojo/public/tools/bindings/generate_type_mappings.py @@ -149,7 +149,7 @@ def main(): for path in params.dependency: typemaps.update(ReadTypemap(path)) - WriteFile(json.dumps({'c++': typemaps}, indent=2), params.output) + WriteFile(json.dumps({'c++': typemaps}, indent=2).encode(), params.output) if __name__ == '__main__': diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl index f353ac79a08..1093c7ff5fe 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl @@ -2,6 +2,12 @@ Macro for enum definition, and the declaration of associated functions. ---#} +{%- macro kythe_annotation(name) %} +{%- if enable_kythe_annotations %} +// @generated_from: {{name}} +{%- endif %} +{%- endmacro %} + {%- macro enum_forward(enum) %} {%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %} enum class {{enum_name}} : int32_t; @@ -10,11 +16,15 @@ enum class {{enum_name}} : int32_t; {%- macro enum_decl(enum, export_attribute) %} {%- set enum_name = enum|get_name_for_kind(flatten_nested_kind=True) %} +{%- set full_enum_name = enum|get_full_mojom_name_for_kind() %} +{{ kythe_annotation(full_enum_name) }} enum class {{enum_name}} : int32_t { {%- for field in enum.fields %} {%- if field.value %} + {{ kythe_annotation("%s.%s"|format(full_enum_name, field.name)) }} {{field.name}} = {{field.value|expression_to_text}}, {%- else %} + {{ kythe_annotation("%s.%s"|format(full_enum_name, field.name)) }} {{field.name}}, {%- endif %} {%- endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl index 51c106ed7ff..03343948630 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl @@ -9,6 +9,9 @@ class {{interface.name}}RequestValidator; class {{interface.name}}ResponseValidator; {%- endif %} +{%- set interface_prefix = "%s.%s"|format(module_prefix, interface.name) %} + +{{ kythe_annotation(interface_prefix) }} class {{export_attribute}} {{interface.name}} : public {{interface.name}}InterfaceBase { public: @@ -38,11 +41,13 @@ class {{export_attribute}} {{interface.name}} {#--- Enums #} {%- for enum in interface.enums %} + {{ kythe_annotation(enum|get_full_mojom_name_for_kind()) }} using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}}; {%- endfor %} {#--- Constants #} {%- for constant in interface.constants %} + {{ kythe_annotation("%s.%s"|format(interface_prefix, constant.name)) }} static {{constant|format_constant_declaration(nested=True)}}; {%- endfor %} @@ -54,11 +59,13 @@ class {{export_attribute}} {{interface.name}} {%- if method.sync %} // Sync method. This signature is used by the client side; the service side // should implement the signature with callback below. + {{ kythe_annotation("%s.%s"|format(interface_prefix, method.name)) }} virtual bool {{method.name}}({{interface_macros.declare_sync_method_params("", method)}}); {%- endif %} using {{method.name}}Callback = {{interface_macros.declare_callback(method, for_blink)}}; {%- endif %} + {{ kythe_annotation("%s.%s"|format(interface_prefix, method.name)) }} virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0; {%- endfor %} }; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index b60b926045f..906eae02b6b 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl @@ -431,7 +431,7 @@ bool {{class_name}}StubDispatch::Accept( {{alloc_params(method.param_struct, "params", "message", desc)| indent(4)}} // A null |impl| means no implementation was bound. - assert(impl); + DCHECK(impl); impl->{{method.name}}({{pass_params(method.parameters)}}); return true; {%- else %} @@ -494,7 +494,7 @@ bool {{class_name}}StubDispatch::AcceptWithResponder( message->has_flag(mojo::Message::kFlagIsSync), std::move(responder)); // A null |impl| means no implementation was bound. - assert(impl); + DCHECK(impl); impl->{{method.name}}( {%- if method.parameters -%}{{pass_params(method.parameters)}}, {% endif -%}std::move(callback)); return true; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl index a14d5112656..63085aaec91 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl @@ -30,6 +30,12 @@ namespace {{variant}} { {%- endfor %} {%- endmacro %} +{%- macro kythe_annotation(name) %} +{%- if enable_kythe_annotations %} +// @generated_from: {{name}} +{%- endif %} +{%- endmacro %} + #ifndef {{header_guard}} #define {{header_guard}} @@ -46,9 +52,6 @@ namespace {{variant}} { #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h" #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h" -{%- if for_blink %} -#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h" -{%- endif %} {%- endif %} {% if not disallow_native_types %} @@ -60,6 +63,12 @@ namespace {{variant}} { #include "{{export_header}}" {%- endif %} +{% if enable_kythe_annotations -%} +#ifdef KYTHE_IS_RUNNING +#pragma kythe_inline_metadata "Metadata comment" +#endif +{%- endif %} + {%- if variant %} {%- for namespace in namespaces_as_array %} namespace {{namespace}} { @@ -95,6 +104,8 @@ using {{enum|get_name_for_kind(flatten_nested_kind=True)}} = mojo::NativeEnum; {{namespace_begin()}} +{%- set module_prefix = "%s"|format(namespaces_as_array|join(".")) %} + {#- These are non-variant header only. #} {%- if not variant %} @@ -133,6 +144,7 @@ using {{enum.name}} = {{enum.name}}; // Alias for definition in the parent name {#--- Constants #} {%- for constant in module.constants %} +{{ kythe_annotation("%s.%s"|format(module_prefix, constant.name)) }} {{constant|format_constant_declaration}}; {%- endfor %} @@ -166,9 +178,6 @@ typedef mojo::StructPtr<{{union.name}}> {{union.name}}Ptr; {% for interface in interfaces %} class {{interface.name}}; using {{interface.name}}Ptr = mojo::InterfacePtr<{{interface.name}}>; -{%- if for_blink %} -using Revocable{{interface.name}}Ptr = ::blink::RevocableInterfacePtr<{{interface.name}}>; -{%- endif %} using {{interface.name}}PtrInfo = mojo::InterfacePtrInfo<{{interface.name}}>; using ThreadSafe{{interface.name}}Ptr = mojo::ThreadSafeInterfacePtr<{{interface.name}}>; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl index f6ee8a61f3e..200a00029c9 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl @@ -27,6 +27,12 @@ #include "{{export_header}}" {%- endif %} +{% if enable_kythe_annotations -%} +#ifdef KYTHE_IS_RUNNING +#pragma kythe_inline_metadata "Metadata comment" +#endif +{%- endif %} + namespace mojo { namespace internal { class ValidationContext; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl index 0c2e6e4492a..994069aa6b7 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl @@ -69,6 +69,12 @@ namespace {{namespace}} { #include "{{export_header}}" {%- endif %} +{% if enable_kythe_annotations -%} +#ifdef KYTHE_IS_RUNNING +#pragma kythe_inline_metadata "Metadata comment" +#endif +{%- endif %} + {{namespace_begin()}} {#--- Struct Forward Declarations -#} @@ -105,8 +111,10 @@ namespace internal { {{namespace_begin()}} +{%- set module_prefix = "%s"|format(namespaces_as_array|join(".")) %} + {#--- Enums #} -{%- from "enum_macros.tmpl" import enum_decl%} +{%- from "enum_macros.tmpl" import enum_decl with context %} {%- for enum in all_enums %} {%- if enum|is_native_only_kind %} using {{enum|get_name_for_kind(flatten_nested_kind=True)}} = mojo::NativeEnum; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index b4f2a452191..28b8a6f217c 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl @@ -30,6 +30,12 @@ namespace {{variant}} { {%- endfor %} {%- endmacro %} +{%- macro kythe_annotation(name) %} +{%- if enable_kythe_annotations %} +// @generated_from: {{name}} +{%- endif %} +{%- endmacro %} + #ifndef {{header_guard}} #define {{header_guard}} @@ -91,7 +97,6 @@ namespace {{variant}} { every use of {Inlined}StructPtr. #} #include "mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h" #include "mojo/public/cpp/bindings/lib/wtf_hash_util.h" -#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h" #include "third_party/blink/renderer/platform/wtf/hash_functions.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" {%- endif %} @@ -105,9 +110,6 @@ namespace {{variant}} { #include "mojo/public/cpp/bindings/lib/control_message_handler.h" #include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h" #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h" -{%- if for_blink %} -#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h" -{%- endif %} {%- endif %} {% if not disallow_native_types %} @@ -123,6 +125,12 @@ namespace {{variant}} { #include "{{export_header}}" {%- endif %} +{% if enable_kythe_annotations -%} +#ifdef KYTHE_IS_RUNNING +#pragma kythe_inline_metadata "Metadata comment" +#endif +{%- endif %} + {#--- WTF enum hashing #} {%- from "enum_macros.tmpl" import enum_hash_blink%} {%- if for_blink %} @@ -135,6 +143,8 @@ namespace {{variant}} { {{namespace_begin()}} +{%- set module_prefix = "%s"|format(namespaces_as_array|join(".")) %} + {#--- Interfaces -#} {% for interface in interfaces %} {% include "interface_declaration.tmpl" %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl index 5571e8449f9..5f11278b57b 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl @@ -17,12 +17,10 @@ struct Serializer<{{data_view}}, MaybeConstUserType> { SerializationContext* context) { if (CallIsNullIfExists<Traits>(input)) return; - void* custom_context = CustomContextHelper<Traits>::SetUp(input, context); {{struct_macros.serialize( struct, struct.name ~ " struct", - "CallWithContext(Traits::%s, input, custom_context)", "(*output)", + "Traits::%s(input)", "(*output)", "buffer", "context", True)|indent(2)}} - CustomContextHelper<Traits>::TearDown(input, custom_context); } static bool Deserialize({{data_type}}* input, diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl index e14169a2630..7e61dde2112 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl @@ -1,3 +1,9 @@ +{%- macro kythe_annotation(name) %} +{%- if enable_kythe_annotations %} +// @generated_from: {{name}} +{%- endif %} +{%- endmacro %} + {%- set class_name = union.name ~ "_Data" -%} {%- set enum_name = union.name ~ "_Tag" -%} {%- import "struct_macros.tmpl" as struct_macros %} @@ -59,6 +65,7 @@ class {{export_attribute}} {{class_name}} { enum class {{enum_name}} : uint32_t { {% for field in union.fields %} + {{ kythe_annotation("%s.%s"|format(union|get_full_mojom_name_for_kind(), field.name)) }} {{field.name|upper}}, {%- endfor %} }; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl index 4e39774b607..3e98edeb514 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl @@ -18,8 +18,6 @@ struct Serializer<{{data_view}}, MaybeConstUserType> { writer->data()->set_null(); return; } - void* custom_context = CustomContextHelper<Traits>::SetUp(input, context); - if (!inlined) writer->Allocate(buffer); @@ -28,16 +26,15 @@ struct Serializer<{{data_view}}, MaybeConstUserType> { // TODO(azani): Handle unknown and objects. // Set the not-null flag. result->size = kUnionDataSize; - result->tag = CallWithContext(Traits::GetTag, input, custom_context); + result->tag = Traits::GetTag(input); switch (result->tag) { {%- for field in union.fields %} {%- set name = field.name %} {%- set kind = field.kind %} {%- set serializer_type = kind|unmapped_type_for_serializer %} case {{data_view}}::Tag::{{field.name|upper}}: { - decltype(CallWithContext(Traits::{{name}}, input, custom_context)) - in_{{name}} = CallWithContext(Traits::{{name}}, input, - custom_context); + decltype(Traits::{{name}}(input)) + in_{{name}} = Traits::{{name}}(input); {%- if kind|is_object_kind %} typename decltype(result->data.f_{{name}})::BaseType::BufferWriter value_writer; @@ -88,8 +85,6 @@ struct Serializer<{{data_view}}, MaybeConstUserType> { } {%- endfor %} } - - CustomContextHelper<Traits>::TearDown(input, custom_context); } static bool Deserialize({{data_type}}* input, diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl index e03fd0cb3e2..801c01523bd 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl @@ -1,3 +1,6 @@ +{%- set struct_prefix = "%s.%s"|format(module_prefix, struct.name) %} + +{{ kythe_annotation(struct_prefix) }} class {{export_attribute}} {{struct.name}} { public: using DataView = {{struct.name}}DataView; @@ -5,11 +8,13 @@ class {{export_attribute}} {{struct.name}} { {#--- Enums #} {%- for enum in struct.enums -%} + {{ kythe_annotation(enum|get_full_mojom_name_for_kind()) }} using {{enum.name}} = {{enum|get_name_for_kind(flatten_nested_kind=True)}}; {%- endfor %} {#--- Constants #} {%- for constant in struct.constants %} + {{ kythe_annotation("%s.%s"|format(struct_prefix, constant.name)) }} static {{constant|format_constant_declaration(nested=True)}}; {%- endfor %} @@ -119,6 +124,7 @@ class {{export_attribute}} {{struct.name}} { {% for field in struct.fields %} {%- set type = field.kind|cpp_wrapper_type %} {%- set name = field.name %} + {{ kythe_annotation("%s.%s"|format(struct_prefix, name)) }} {{type}} {{name}}; {%- endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl index a0be109b030..40603a7fe53 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_declaration.tmpl @@ -1,3 +1,6 @@ +{%- set union_prefix = "%s.%s"|format(module_prefix, union.name) %} + +{{ kythe_annotation(union_prefix) }} class {{export_attribute}} {{union.name}} { public: using DataView = {{union.name}}DataView; @@ -55,8 +58,10 @@ class {{export_attribute}} {{union.name}} { } {% for field in union.fields %} + {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }} bool is_{{field.name}}() const { return tag_ == Tag::{{field.name|upper}}; } + {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }} {{field.kind|cpp_union_getter_return_type}} get_{{field.name}}() const { DCHECK(tag_ == Tag::{{field.name|upper}}); {%- if field.kind|is_object_kind or @@ -67,6 +72,7 @@ class {{export_attribute}} {{union.name}} { {%- endif %} } + {{ kythe_annotation("%s.%s"|format(union_prefix, field.name)) }} void set_{{field.name}}( {{field.kind|cpp_wrapper_param_type_new}} {{field.name}}); {%- endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl index 99859e0e986..c2541994f00 100644 --- a/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/java_templates/enum_definition.tmpl @@ -1,49 +1,45 @@ {%- macro enum_value(enum, field, index) -%} {%- if field.value -%} -(int) ({{field.value|expression_to_text('i32')}}) +{{field.value|expression_to_text('i32')}}; {%- elif index == 0 -%} -0 +{{field.numeric_value}}; {%- else -%} -{{enum.fields[index - 1]|name}} + 1 +{{field.numeric_value}}; // {{enum.fields[index - 1]|name}} + 1 {%- endif -%} {%- endmacro -%} {%- macro enum_def(enum, top_level) -%} public {{ 'static ' if not top_level }}final class {{enum|name}} { - + private static final boolean IS_EXTENSIBLE = {% if enum.extensible %}true{% else %}false{% endif %}; {% for field in enum.fields %} - public static final int {{field|name}} = {{enum_value(enum, field, loop.index0)}}; -{% endfor %} + public static final int {{field|name}} = {{enum_value(enum, field, loop.index0)}} +{%- endfor %} -{%- if enum.min_value is not none %} - public static final int MIN_VALUE = (int) ({{enum.min_value}}); -{%- endif %} -{%- if enum.max_value is not none %} - public static final int MAX_VALUE = (int) ({{enum.max_value}}); -{%- endif %} +{%- if enum|covers_continuous_range %} - private static final boolean IS_EXTENSIBLE = {% if enum.extensible %}true{% else %}false{% endif %}; + public static boolean isKnownValue(int value) { + return value >= {{enum.min_value}} && value <= {{enum.max_value}}; + } +{%- else %} public static boolean isKnownValue(int value) { -{%- if enum.fields %} +{%- if enum.fields %} switch (value) { -{%- for enum_field in enum.fields|groupby('numeric_value') %} +{%- for enum_field in enum.fields|groupby('numeric_value') %} case {{enum_field[0]}}: -{%- endfor %} +{%- endfor %} return true; } -{%- endif %} +{%- endif %} return false; } +{%- endif %} public static void validate(int value) { - if (IS_EXTENSIBLE || isKnownValue(value)) - return; - + if (IS_EXTENSIBLE || isKnownValue(value)) return; throw new DeserializationException("Invalid enum value."); } private {{enum|name}}() {} - } {%- endmacro -%} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl index b6f1293d96d..affa4d09650 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/enum_definition.tmpl @@ -2,7 +2,10 @@ {# TODO: Less generic enum annotations would be nice. We do it this way because the bindings generator is still too stupid to generate the right integral constants directly. #} +{%- set enum_name = enum|lite_closure_type -%} + {% if generate_closure_exports -%} +goog.provide('{{enum_name}}'); goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec'); {%- endif %} /** @@ -15,7 +18,7 @@ goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec'); * @enum {number} * @export */ -{{enum_parent}}.{{enum.name}} = { +{{enum_name}} = { {# Set up the enum here, but fill out the values later. #} {%- for field in enum.fields %} {{field.name}}: 0, @@ -31,11 +34,11 @@ goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec'); {# Suppress type checks since we're assigning number into an enum. #} /** @suppress {checkTypes} */ {%- if field.value %} -{{enum_parent}}.{{enum.name}}.{{field.name}} = {{field.value|expression_to_text_lite}}; +{{enum_name}}.{{field.name}} = {{field.value|expression_to_text_lite}}; {%- elif loop.first %} -{{enum_parent}}.{{enum.name}}.{{field.name}} = 0; +{{enum_name}}.{{field.name}} = 0; {%- else %} -{{enum_parent}}.{{enum.name}}.{{field.name}} = {{enum_parent}}.{{enum.name}}.{{enum.fields[loop.index0 - 1].name}} + 1; +{{enum_name}}.{{field.name}} = {{enum_name}}.{{enum.fields[loop.index0 - 1].name}} + 1; {%- endif %} {%- endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl index 874b97ff4ba..53cce1708a3 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl @@ -17,6 +17,14 @@ */ {% endmacro %} +{% if generate_closure_exports -%} +goog.provide('{{module.namespace}}.{{interface.name}}'); +goog.provide('{{module.namespace}}.{{interface.name}}CallbackRouter'); +goog.provide('{{module.namespace}}.{{interface.name}}Interface'); +goog.provide('{{module.namespace}}.{{interface.name}}Proxy'); +goog.provide('{{module.namespace}}.{{interface.name}}Request'); +{% endif %} + /** @export */ {{module.namespace}}.{{interface.name}}Request = class { /** @param {!MojoHandle} handle */ @@ -120,6 +128,8 @@ {%- endif %} impl.{{method.name}}.bind(impl)); {%- endfor %} + /** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */ + this.onConnectionError = this.target_.getConnectionErrorEventRouter(); } /** @@ -165,7 +175,7 @@ {#--- Enums #} {% from "lite/enum_definition.tmpl" import enum_def with context %} {%- for enum in interface.enums %} -{{ enum_def("%s.%sSpec"|format(module.namespace, interface.name), +{{ enum_def("%s.%s"|format(module.namespace, interface.name), "%s.%s"|format(module.namespace, interface.name), enum) }} {%- endfor %} @@ -193,7 +203,7 @@ {%- set interface_message_id = interface.mojom_name ~ "_" ~ method.mojom_name %} /** - * @export {!mojo.internal.interfaceSupport.InterfaceCallbackTarget} + * @public {!mojo.internal.interfaceSupport.InterfaceCallbackTarget} */ this.{{method.name}} = new mojo.internal.interfaceSupport.InterfaceCallbackTarget( @@ -210,6 +220,8 @@ this.{{method.name}}.createTargetHandler(false /* expectsResponse */)); {%- endif %} {%- endfor %} + /** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */ + this.onConnectionError = this.target_.getConnectionErrorEventRouter(); } /** diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl index b9b2e32e0aa..a02c7a32077 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/mojom-lite.js.tmpl @@ -8,8 +8,11 @@ goog.require('mojo.internal'); {%- if interfaces %} goog.require('mojo.internal.interfaceSupport'); {%- endif %} -{% endif %} - +{% for kind in module.imported_kinds.values() %} +goog.require('{{kind|lite_js_import_name}}'); +{%- endfor %} +{% else %} mojo.internal.exportModule('{{module.namespace}}'); +{% endif %} {% include "lite/module_definition.tmpl" %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/struct_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/struct_definition.tmpl index fa6bd2e71b3..98b6f1fb33d 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/struct_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/struct_definition.tmpl @@ -3,7 +3,7 @@ * @const { {{constant.kind|lite_closure_type_with_nullability}} } * @export */ -{{module.namespace}}.{{struct.name}}.{{constant.name}} = +{{module.namespace}}.{{struct.name}}_{{constant.name}} = {{constant.value|expression_to_text_lite}}; {% endfor %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/union_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/union_definition.tmpl index ee637012d2b..2174ecd89aa 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/union_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/union_definition.tmpl @@ -1,3 +1,6 @@ +{% if generate_closure_exports -%} +goog.provide('{{module.namespace}}.{{union.name}}'); +{% endif %} mojo.internal.Union( {{module.namespace}}.{{union.name}}Spec.$, '{{union.name}}', diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 2e6e20a78c9..b8070e6f8bd 100644 --- a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -268,7 +268,7 @@ class Generator(generator.Generator): for typename in self.module.structs + all_enums + self.module.unions) headers = set() - for typename, typemap in self.typemap.iteritems(): + for typename, typemap in self.typemap.items(): if typename in types: headers.update(typemap.get("public_headers", [])) return sorted(headers) @@ -294,6 +294,7 @@ class Generator(generator.Generator): "all_enums": all_enums, "disallow_interfaces": self.disallow_interfaces, "disallow_native_types": self.disallow_native_types, + "enable_kythe_annotations": self.enable_kythe_annotations, "enums": self.module.enums, "export_attribute": self.export_attribute, "export_header": self.export_header, @@ -337,6 +338,7 @@ class Generator(generator.Generator): "format_constant_declaration": self._FormatConstantDeclaration, "get_container_validate_params_ctor_args": self._GetContainerValidateParamsCtorArgs, + "get_full_mojom_name_for_kind": self._GetFullMojomNameForKind, "get_name_for_kind": self._GetNameForKind, "get_pad": pack.GetPad, "get_qualified_name_for_kind": self._GetQualifiedNameForKind, diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py index 8097af35ffc..7b7fc8375c0 100644 --- a/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -339,7 +339,6 @@ def ExpressionToText(context, token, kind_spec=''): if isinstance(token, mojom.NamedValue): return _TranslateNamedValue(token) if kind_spec.startswith('i') or kind_spec.startswith('u'): - # Add Long suffix to all integer literals. number = ast.literal_eval(token.lstrip('+ ')) if not isinstance(number, (int, long)): raise ValueError('got unexpected type %r for int literal %r' % ( @@ -348,6 +347,8 @@ def ExpressionToText(context, token, kind_spec=''): # equivalent signed long. if number >= 2 ** 63: number -= 2 ** 64 + if number < 2 ** 31 and number >= -2 ** 31: + return '%d' % number return '%dL' % number if isinstance(token, mojom.BuiltinValue): if token.value == 'double.INFINITY': @@ -421,6 +422,14 @@ def TempDir(): finally: shutil.rmtree(dirname) +def EnumCoversContinuousRange(kind): + if not kind.fields: + return False + number_of_unique_keys = len(set(map(lambda field: field.numeric_value, kind.fields))) + if kind.max_value - kind.min_value + 1 != number_of_unique_keys: + return False + return True + class Generator(generator.Generator): def _GetJinjaExports(self): return { @@ -436,6 +445,7 @@ class Generator(generator.Generator): 'array_expected_length': GetArrayExpectedLength, 'array': GetArrayKind, 'constant_value': ConstantValue, + 'covers_continuous_range': EnumCoversContinuousRange, 'decode_method': DecodeMethod, 'default_value': DefaultValue, 'encode_method': EncodeMethod, diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py index bc8bc63a39f..4b53f3ec90d 100644 --- a/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py +++ b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py @@ -301,10 +301,12 @@ class Generator(generator.Generator): "js_type": self._JavaScriptType, "lite_default_value": self._LiteJavaScriptDefaultValue, "lite_js_type": self._LiteJavaScriptType, + "lite_js_import_name": self._LiteJavaScriptImportName, "method_passes_associated_kinds": mojom.MethodPassesAssociatedKinds, "namespace_declarations": self._NamespaceDeclarations, "closure_type_with_nullability": self._ClosureTypeWithNullability, "lite_closure_param_type": self._LiteClosureParamType, + "lite_closure_type": self._LiteClosureType, "lite_closure_type_with_nullability": self._LiteClosureTypeWithNullability, "lite_closure_field_type": self._LiteClosureFieldType, @@ -441,8 +443,13 @@ class Generator(generator.Generator): name.append(named_kind.module.namespace) if named_kind.parent_kind: name.append(named_kind.parent_kind.name) - name.append("" + named_kind.name) - name = ".".join(name) + + if mojom.IsEnumKind(kind) and named_kind.parent_kind: + name = ".".join(name) + name += "_" + named_kind.name + else: + name.append("" + named_kind.name) + name = ".".join(name) if (mojom.IsStructKind(kind) or mojom.IsUnionKind(kind) or mojom.IsEnumKind(kind)): @@ -532,7 +539,10 @@ class Generator(generator.Generator): if named_kind.module: name.append(named_kind.module.namespace) if named_kind.parent_kind: - name.append(named_kind.parent_kind.name + "Spec") + parent_name = named_kind.parent_kind.name + if mojom.IsStructKind(named_kind.parent_kind): + parent_name += "Spec" + name.append(parent_name) name.append(named_kind.name) name = ".".join(name) @@ -552,6 +562,15 @@ class Generator(generator.Generator): return name + def _LiteJavaScriptImportName(self, kind): + name = [] + if kind.parent_kind: + name.append(self._LiteJavaScriptImportName(kind.parent_kind)) + elif kind.module: + name.append(kind.module.namespace) + name.append(kind.name) + return '.'.join(name) + def _JavaScriptDefaultValue(self, field): if field.default: if mojom.IsStructKind(field.kind): diff --git a/chromium/mojo/public/tools/bindings/mojom.gni b/chromium/mojo/public/tools/bindings/mojom.gni index ac896c8dea2..0c2e3780458 100644 --- a/chromium/mojo/public/tools/bindings/mojom.gni +++ b/chromium/mojo/public/tools/bindings/mojom.gni @@ -40,6 +40,10 @@ declare_args() { # where compilation is supported, any mojom target "foo" will also have a # corresponding "foo_js_library_for_compile" target generated. enable_mojom_closure_compile = closure_compile && optimize_webui + + # Enable adding annotations to generated C++ headers that are used for + # cross-references in CodeSearch. + enable_kythe_annotations = false } # NOTE: We would like to avoid scrambling message IDs where it doesn't add @@ -679,6 +683,10 @@ template("mojom") { "base/component_export.h", ] } + + if (enable_kythe_annotations) { + args += [ "--enable_kythe_annotations" ] + } } } else { group(generator_cpp_message_ids_target_name) { @@ -910,6 +918,10 @@ template("mojom") { invoker.support_lazy_serialization) { args += [ "--support_lazy_serialization" ] } + + if (enable_kythe_annotations) { + args += [ "--enable_kythe_annotations" ] + } } } diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py index d847f4b1a4d..72f23d86fa9 100755 --- a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -5,9 +5,15 @@ """The frontend for the Mojo bindings system.""" +from __future__ import print_function import argparse -import cPickle + +try: + import cPickle as pickle +except ImportError: + import pickle + import hashlib import importlib import json @@ -62,7 +68,7 @@ def LoadGenerators(generators_string): for generator_name in [s.strip() for s in generators_string.split(",")]: language = generator_name.lower() if language not in _BUILTIN_GENERATORS: - print "Unknown generator name %s" % generator_name + print("Unknown generator name %s" % generator_name) sys.exit(1) generator_module = importlib.import_module( "generators.%s" % _BUILTIN_GENERATORS[language]) @@ -158,7 +164,7 @@ class MojomProcessor(object): for filename in typemaps: with open(filename) as f: typemaps = json.loads("".join(filter(no_comments, f.readlines()))) - for language, typemap in typemaps.iteritems(): + for language, typemap in typemaps.items(): language_map = self._typemap.get(language, {}) language_map.update(typemap) self._typemap[language] = language_map @@ -170,8 +176,8 @@ class MojomProcessor(object): return self._processed_files[rel_filename.path] if rel_filename.path in imported_filename_stack: - print "%s: Error: Circular dependency" % rel_filename.path + \ - MakeImportStackMessage(imported_filename_stack + [rel_filename.path]) + print("%s: Error: Circular dependency" % rel_filename.path + \ + MakeImportStackMessage(imported_filename_stack + [rel_filename.path])) sys.exit(1) tree = _UnpickleAST(_FindPicklePath(rel_filename, args.gen_directories + @@ -202,7 +208,7 @@ class MojomProcessor(object): if self._should_generate(rel_filename.path): AddComputedData(module) - for language, generator_module in generator_modules.iteritems(): + for language, generator_module in generator_modules.items(): generator = generator_module.Generator( module, args.output_dir, typemap=self._typemap.get(language, {}), variant=args.variant, bytecode_path=args.bytecode_path, @@ -215,7 +221,8 @@ class MojomProcessor(object): disallow_native_types=args.disallow_native_types, disallow_interfaces=args.disallow_interfaces, generate_message_ids=args.generate_message_ids, - generate_fuzzing=args.generate_fuzzing) + generate_fuzzing=args.generate_fuzzing, + enable_kythe_annotations=args.enable_kythe_annotations) filtered_args = [] if hasattr(generator_module, 'GENERATOR_PREFIX'): prefix = '--' + generator_module.GENERATOR_PREFIX + '_' @@ -278,32 +285,33 @@ def _PickleAST(ast, output_file): fileutil.EnsureDirectoryExists(full_dir) try: - WriteFile(cPickle.dumps(ast), output_file) - except (IOError, cPickle.PicklingError) as e: - print "%s: Error: %s" % (output_file, str(e)) + WriteFile(pickle.dumps(ast), output_file) + except (IOError, pickle.PicklingError) as e: + print("%s: Error: %s" % (output_file, str(e))) sys.exit(1) def _UnpickleAST(input_file): - try: - with open(input_file, "rb") as f: - return cPickle.load(f) - except (IOError, cPickle.UnpicklingError) as e: - print "%s: Error: %s" % (input_file, str(e)) - sys.exit(1) + try: + with open(input_file, "rb") as f: + return pickle.load(f) + except (IOError, pickle.UnpicklingError) as e: + print("%s: Error: %s" % (input_file, str(e))) + sys.exit(1) + def _ParseFile(args, rel_filename): try: with open(rel_filename.path) as f: source = f.read() except IOError as e: - print "%s: Error: %s" % (rel_filename.path, e.strerror) + print("%s: Error: %s" % (rel_filename.path, e.strerror)) sys.exit(1) try: tree = Parse(source, rel_filename.path) RemoveDisabledDefinitions(tree, args.enabled_features) except Error as e: - print "%s: Error: %s" % (rel_filename.path, str(e)) + print("%s: Error: %s" % (rel_filename.path, str(e))) sys.exit(1) _PickleAST(tree, _GetPicklePath(rel_filename, args.output_dir)) @@ -371,16 +379,16 @@ def _VerifyImportDeps(args, __): full_target_name = "//" + target_prefix_without_gen_dir.rsplit( "/", 1)[0] + ":" + target_name - print ">>> File \"%s\"" % (filename) - print ">>> from target \"%s\"" % (full_target_name) - print ">>> is missing dependencies for the following imports:\n%s" % \ - list(mojom_imports.difference(sources)) + print(">>> File \"%s\"" % filename) + print(">>> from target \"%s\"" % full_target_name) + print(">>> is missing dependencies for the following imports:\n%s" % list( + mojom_imports.difference(sources))) sys.exit(1) source_filename, _ = os.path.splitext(rel_path.relative_path()) output_file = source_filename + '.v' output_file_path = os.path.join(args.gen_dir, output_file) - WriteFile("", output_file_path) + WriteFile(b"", output_file_path) return 0 @@ -497,6 +505,11 @@ def main(): "--generate_fuzzing", action="store_true", help="Generates additional bindings for fuzzing in JS.") + generate_parser.add_argument( + "--enable_kythe_annotations", + action="store_true", + help="Adds annotations for kythe metadata generation.") + generate_parser.set_defaults(func=_Generate) precompile_parser = subparsers.add_parser("precompile", diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index 045800f8930..709dd22cfcd 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -4,13 +4,15 @@ """Code shared by the various language-specific code generators.""" +from __future__ import print_function + from functools import partial import os.path import re -import module as mojom +import mojom.generate.module as mojom import mojom.fileutil as fileutil -import pack +import mojom.generate.pack as pack def ExpectedArraySize(kind): @@ -165,7 +167,7 @@ class Generator(object): export_header=None, generate_non_variant_code=False, support_lazy_serialization=False, disallow_native_types=False, disallow_interfaces=False, generate_message_ids=False, - generate_fuzzing=False): + generate_fuzzing=False, enable_kythe_annotations=False): self.module = module self.output_dir = output_dir self.typemap = typemap or {} @@ -181,10 +183,11 @@ class Generator(object): self.disallow_interfaces = disallow_interfaces self.generate_message_ids = generate_message_ids self.generate_fuzzing = generate_fuzzing + self.enable_kythe_annotations = enable_kythe_annotations def Write(self, contents, filename): if self.output_dir is None: - print contents + print(contents) return full_path = os.path.join(self.output_dir, filename) WriteFile(contents, full_path) diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py index 79264a0d23a..18a410159cb 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -740,6 +740,7 @@ class Module(object): self.kinds = {} self.attributes = attributes self.imports = [] + self.imported_kinds = {} def __repr__(self): # Gives us a decent __repr__ for modules. diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py index 9187364d1e2..b30949e3f8c 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/pack.py @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import module as mojom +import mojom.generate.module as mojom # This module provides a mechanism for determining the packed order and offsets # of a mojom.Struct. @@ -165,7 +165,7 @@ class PackedStruct(object): # Then find first slot that each field will fit. for src_field in src_fields[1:]: last_field = dst_fields[0] - for i in xrange(1, len(dst_fields)): + for i in range(1, len(dst_fields)): next_field = dst_fields[i] offset, bit = GetFieldOffset(src_field, last_field) if offset + src_field.size <= next_field.offset: @@ -190,16 +190,16 @@ class ByteInfo(object): def GetByteLayout(packed_struct): total_payload_size = GetPayloadSizeUpToField( packed_struct.packed_fields[-1] if packed_struct.packed_fields else None) - bytes = [ByteInfo() for i in xrange(total_payload_size)] + bytes = [ByteInfo() for i in range(total_payload_size)] limit_of_previous_field = 0 for packed_field in packed_struct.packed_fields: - for i in xrange(limit_of_previous_field, packed_field.offset): + for i in range(limit_of_previous_field, packed_field.offset): bytes[i].is_padding = True bytes[packed_field.offset].packed_fields.append(packed_field) limit_of_previous_field = packed_field.offset + packed_field.size - for i in xrange(limit_of_previous_field, len(bytes)): + for i in range(limit_of_previous_field, len(bytes)): bytes[i].is_padding = True for byte in bytes: diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py index 653a2dfc74d..948ba3d30c7 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/template_expander.py @@ -35,7 +35,7 @@ def UseJinja(path_to_template, **kwargs): def GeneratorInternal(*args, **kwargs2): parameters = generator(*args, **kwargs2) return ApplyTemplate(args[0], path_to_template, parameters, **kwargs) - GeneratorInternal.func_name = generator.func_name + GeneratorInternal.__name__ = generator.__name__ return GeneratorInternal return RealDecorator diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py index cdc9d0e7c42..3d3d53d99f7 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py @@ -10,10 +10,11 @@ representation of a mojom file. When called it's assumed that all imports have already been parsed and converted to ASTs before. """ +import itertools import os import re -import module as mojom +import mojom.generate.module as mojom from mojom.parse import ast def _DuplicateName(values): @@ -128,7 +129,7 @@ def _LookupKind(kinds, spec, scope): to the location where the type is referenced.""" if spec.startswith('x:'): mojom_name = spec[2:] - for i in xrange(len(scope), -1, -1): + for i in range(len(scope), -1, -1): test_spec = 'x:' if i > 0: test_spec += '.'.join(scope[:i]) + '.' @@ -147,7 +148,7 @@ def _LookupValue(values, mojom_name, scope, kind): # enum name. if isinstance(kind, mojom.Enum) and '.' not in mojom_name: mojom_name = '%s.%s' % (kind.spec.split(':', 1)[1], mojom_name) - for i in reversed(xrange(len(scope) + 1)): + for i in reversed(range(len(scope) + 1)): test_spec = '.'.join(scope[:i]) if test_spec: test_spec += '.' @@ -554,6 +555,61 @@ def _Constant(module, parsed_const, parent_kind): module.values[value.GetSpec()] = value return constant + +def _CollectReferencedKinds(module, all_defined_kinds): + """ + Takes a {mojom.Module} object and a list of all defined kinds within that + module, and enumerates the complete dict of user-defined mojom types + (as {mojom.Kind} objects) referenced by the module's own defined kinds (i.e. + as types of struct or union or interface parameters. The returned dict is + keyed by kind spec. + """ + + def extract_referenced_user_kinds(kind): + if mojom.IsArrayKind(kind): + return extract_referenced_user_kinds(kind.kind) + if mojom.IsMapKind(kind): + return (extract_referenced_user_kinds(kind.key_kind) + + extract_referenced_user_kinds(kind.value_kind)) + if mojom.IsInterfaceRequestKind(kind) or mojom.IsAssociatedKind(kind): + return [kind.kind] + if mojom.IsStructKind(kind): + return [kind] + if (mojom.IsInterfaceKind(kind) or mojom.IsEnumKind(kind) or + mojom.IsUnionKind(kind)): + return [kind] + return [] + + def sanitize_kind(kind): + """Removes nullability from a kind""" + if kind.spec.startswith('?'): + return _Kind(module.kinds, kind.spec[1:], + (module.mojom_namespace, '')) + return kind + + referenced_user_kinds = {} + for defined_kind in all_defined_kinds: + if mojom.IsStructKind(defined_kind) or mojom.IsUnionKind(defined_kind): + for field in defined_kind.fields: + for referenced_kind in extract_referenced_user_kinds(field.kind): + sanitized_kind = sanitize_kind(referenced_kind) + referenced_user_kinds[sanitized_kind.spec] = sanitized_kind + + # Also scan for references in parameter lists + for interface in module.interfaces: + for method in interface.methods: + for param in itertools.chain(method.parameters or [], + method.response_parameters or []): + if (mojom.IsStructKind(param.kind) or mojom.IsUnionKind(param.kind) or + mojom.IsEnumKind(param.kind) or + mojom.IsAnyInterfaceKind(param.kind)): + for referenced_kind in extract_referenced_user_kinds(param.kind): + sanitized_kind = sanitize_kind(referenced_kind) + referenced_user_kinds[sanitized_kind.spec] = sanitized_kind + + return referenced_user_kinds + + def _Module(tree, path, imports): """ Args: @@ -604,18 +660,35 @@ def _Module(tree, path, imports): # Second pass expands fields and methods. This allows fields and parameters # to refer to kinds defined anywhere in the mojom. + all_defined_kinds = {} for struct in module.structs: struct.fields = map(lambda field: _StructField(module, field, struct), struct.fields_data) del struct.fields_data + all_defined_kinds[struct.spec] = struct + for enum in struct.enums: + all_defined_kinds[enum.spec] = enum for union in module.unions: union.fields = map(lambda field: _UnionField(module, field, union), union.fields_data) del union.fields_data + all_defined_kinds[union.spec] = union for interface in module.interfaces: interface.methods = map(lambda method: _Method(module, method, interface), interface.methods_data) del interface.methods_data + all_defined_kinds[interface.spec] = interface + for enum in interface.enums: + all_defined_kinds[enum.spec] = enum + for enum in module.enums: + all_defined_kinds[enum.spec] = enum + + all_referenced_kinds = _CollectReferencedKinds(module, + all_defined_kinds.values()) + imported_kind_specs = set(all_referenced_kinds.keys()).difference( + set(all_defined_kinds.keys())) + module.imported_kinds = dict((spec, all_referenced_kinds[spec]) + for spec in imported_kind_specs) return module diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py index e9d78449868..32e4d117db4 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/parse/ast.py @@ -18,7 +18,7 @@ class NodeBase(object): self.lineno = lineno def __eq__(self, other): - return type(self) == type(other) + return isinstance(self, other) # Make != the inverse of ==. (Subclasses shouldn't have to override this.) def __ne__(self, other): diff --git a/chromium/mojo/public/tools/fuzzers/DEPS b/chromium/mojo/public/tools/fuzzers/DEPS deleted file mode 100644 index 9243dcd6900..00000000000 --- a/chromium/mojo/public/tools/fuzzers/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/core/embedder", -] diff --git a/chromium/mojo/public/tools/fuzzers/OWNERS b/chromium/mojo/public/tools/fuzzers/OWNERS deleted file mode 100644 index 08850f42120..00000000000 --- a/chromium/mojo/public/tools/fuzzers/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -per-file *.mojom=set noparent -per-file *.mojom=file://ipc/SECURITY_OWNERS diff --git a/chromium/mojo/public/tools/fuzzers/fuzz_impl.cc b/chromium/mojo/public/tools/fuzzers/fuzz_impl.cc deleted file mode 100644 index d3b10128bd1..00000000000 --- a/chromium/mojo/public/tools/fuzzers/fuzz_impl.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017 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 <utility> - -#include "mojo/public/tools/fuzzers/fuzz.mojom.h" -#include "mojo/public/tools/fuzzers/fuzz_impl.h" - -FuzzImpl::FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request) - : binding_(this, std::move(request)) {} - -FuzzImpl::~FuzzImpl() {} - -void FuzzImpl::FuzzBasic() {} - -void FuzzImpl::FuzzBasicResp(FuzzBasicRespCallback callback) { - std::move(callback).Run(); -} - -void FuzzImpl::FuzzBasicSyncResp(FuzzBasicSyncRespCallback callback) { - std::move(callback).Run(); -} - -void FuzzImpl::FuzzArgs(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b) {} - -void FuzzImpl::FuzzArgsResp(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b, - FuzzArgsRespCallback callback) { - std::move(callback).Run(); -} - -void FuzzImpl::FuzzArgsSyncResp(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b, - FuzzArgsSyncRespCallback callback) { - std::move(callback).Run(); -} - -void FuzzImpl::FuzzAssociated( - fuzz::mojom::FuzzDummyInterfaceAssociatedRequest req) { - associated_bindings_.AddBinding(this, std::move(req)); -} - -void FuzzImpl::Ping() {} diff --git a/chromium/mojo/public/tools/fuzzers/fuzz_impl.h b/chromium/mojo/public/tools/fuzzers/fuzz_impl.h deleted file mode 100644 index d63a7073e2e..00000000000 --- a/chromium/mojo/public/tools/fuzzers/fuzz_impl.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017 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 MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_ -#define MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_ - -#include "mojo/public/cpp/bindings/associated_binding_set.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/tools/fuzzers/fuzz.mojom.h" - -class FuzzImpl : public fuzz::mojom::FuzzInterface, - public fuzz::mojom::FuzzDummyInterface { - public: - explicit FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request); - ~FuzzImpl() override; - - // fuzz::mojom::FuzzInterface: - void FuzzBasic() override; - void FuzzBasicResp(FuzzBasicRespCallback callback) override; - void FuzzBasicSyncResp(FuzzBasicSyncRespCallback callback) override; - void FuzzArgs(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b) override; - - void FuzzArgsResp(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b, - FuzzArgsRespCallback callback) override; - void FuzzArgsSyncResp(fuzz::mojom::FuzzStructPtr a, - fuzz::mojom::FuzzStructPtr b, - FuzzArgsSyncRespCallback callback) override; - - void FuzzAssociated( - fuzz::mojom::FuzzDummyInterfaceAssociatedRequest req) override; - - // fuzz::mojom::FuzzDummyInterface: - void Ping() override; - - /* Expose the binding to the fuzz harness. */ - mojo::Binding<FuzzInterface> binding_; - - private: - mojo::AssociatedBindingSet<FuzzDummyInterface> associated_bindings_; -}; - -#endif // MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_ diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg Binary files differdeleted file mode 100644 index 945b63c4723..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_0.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg Binary files differdeleted file mode 100644 index 41715c8239e..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_1.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_10.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_10.mojomsg Binary files differdeleted file mode 100644 index c19d5c752e9..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_10.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_11.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_11.mojomsg Binary files differdeleted file mode 100644 index 61ba9898037..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_11.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg Binary files differdeleted file mode 100644 index 7b5b3028888..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_2.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg Binary files differdeleted file mode 100644 index d0503715fd2..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_3.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg Binary files differdeleted file mode 100644 index 380c391bbcf..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_4.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg Binary files differdeleted file mode 100644 index 1bf4b452b73..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_5.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg Binary files differdeleted file mode 100644 index 8cffad65f78..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_6.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg Binary files differdeleted file mode 100644 index aeff3d60248..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_7.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg Binary files differdeleted file mode 100644 index 019f9e656e9..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_8.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/message_corpus/message_9.mojomsg b/chromium/mojo/public/tools/fuzzers/message_corpus/message_9.mojomsg Binary files differdeleted file mode 100644 index 61049cf149e..00000000000 --- a/chromium/mojo/public/tools/fuzzers/message_corpus/message_9.mojomsg +++ /dev/null diff --git a/chromium/mojo/public/tools/fuzzers/mojo_fuzzer.proto b/chromium/mojo/public/tools/fuzzers/mojo_fuzzer.proto deleted file mode 100644 index fb17871151f..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_fuzzer.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto2"; - -package mojo_proto_fuzzer; - -message MojoFuzzerMessages { - repeated bytes messages = 1; -}
\ No newline at end of file diff --git a/chromium/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc b/chromium/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc deleted file mode 100644 index 3cc657cf04c..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2017 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 <stddef.h> -#include <stdint.h> - -#include "base/bind.h" -#include "base/containers/flat_map.h" -#include "base/files/file.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/task/task_scheduler/task_scheduler.h" -#include "mojo/core/embedder/embedder.h" -#include "mojo/public/tools/fuzzers/fuzz.mojom.h" -#include "mojo/public/tools/fuzzers/fuzz_impl.h" - -/* Environment for the executable. Initializes the mojo EDK and sets up a - * TaskScheduler, because Mojo messages must be sent and processed from - * TaskRunners. */ -struct Environment { - Environment() : message_loop() { - base::TaskScheduler::CreateAndStartWithDefaultParams( - "MojoFuzzerMessageDumpProcess"); - mojo::core::Init(); - } - - /* Message loop to send messages on. */ - base::MessageLoop message_loop; - - /* Impl to be created. Stored in environment to keep it alive after - * DumpMessages returns. */ - std::unique_ptr<FuzzImpl> impl; -}; - -Environment* env = new Environment(); - -/* MessageReceiver which dumps raw message bytes to disk in the provided - * directory. */ -class MessageDumper : public mojo::MessageReceiver { - public: - explicit MessageDumper(std::string directory) - : directory_(directory), count_(0) {} - - bool Accept(mojo::Message* message) override { - base::FilePath path = directory_.Append(FILE_PATH_LITERAL("message_") + - base::NumberToString(count_++) + - FILE_PATH_LITERAL(".mojomsg")); - - base::File file(path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - if (!file.IsValid()) { - LOG(ERROR) << "Failed to create mojo message file: " << path.value(); - return false; - } - - size_t size = message->data_num_bytes(); - const char* data = reinterpret_cast<const char*>(message->data()); - int ret = file.WriteAtCurrentPos(data, size); - if (ret != static_cast<int>(size)) { - LOG(ERROR) << "Failed to write " << size << " bytes."; - return false; - } - return true; - } - - base::FilePath directory_; - int count_; -}; - -/* Returns a FuzzUnion with fuzz_bool initialized. */ -auto GetBoolFuzzUnion() { - fuzz::mojom::FuzzUnionPtr union_bool = fuzz::mojom::FuzzUnion::New(); - union_bool->set_fuzz_bool(true); - return union_bool; -} - -/* Returns a FuzzUnion with fuzz_struct_map initialized. Takes in a - * FuzzDummyStructPtr to use within the fuzz_struct_map value. */ -auto GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStructPtr in) { - fuzz::mojom::FuzzUnionPtr union_struct_map = fuzz::mojom::FuzzUnion::New(); - base::flat_map<std::string, fuzz::mojom::FuzzDummyStructPtr> struct_map; - struct_map["fuzz"] = std::move(in); - union_struct_map->set_fuzz_struct_map(std::move(struct_map)); - return union_struct_map; -} - -/* Returns a FuzzUnion with fuzz_complex initialized. Takes in a FuzzUnionPtr - * to use within the fuzz_complex value. */ -auto GetComplexFuzzUnion(fuzz::mojom::FuzzUnionPtr in) { - std::remove_reference<decltype(in->get_fuzz_complex())>::type complex_map; - std::remove_reference<decltype(complex_map.value()[0])>::type outer; - std::remove_reference<decltype( - outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner; - std::remove_reference<decltype(inner['z'])>::type center; - - center.emplace(); - center.value().push_back(std::move(in)); - inner['z'] = std::move(center); - outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner); - complex_map.emplace(); - complex_map.value().push_back(std::move(outer)); - - fuzz::mojom::FuzzUnionPtr union_complex = fuzz::mojom::FuzzUnion::New(); - union_complex->set_fuzz_complex(std::move(complex_map)); - return union_complex; -} - -/* Returns a populated value for FuzzStruct->fuzz_primitive_array. */ -auto GetFuzzStructPrimitiveArrayValue() { - decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_array) primitive_array; - primitive_array = {'f', 'u', 'z', 'z'}; - return primitive_array; -} - -/* Returns a populated value for FuzzStruct->fuzz_primitive_map. */ -auto GetFuzzStructPrimitiveMapValue() { - decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_map) primitive_map; - primitive_map["fuzz"] = 'z'; - return primitive_map; -} - -/* Returns a populated value for FuzzStruct->fuzz_array_map. */ -auto GetFuzzStructArrayMapValue() { - decltype(fuzz::mojom::FuzzStruct::fuzz_array_map) array_map; - array_map["fuzz"] = {"fuzz1", "fuzz2"}; - return array_map; -} - -/* Returns a populated value for FuzzStruct->fuzz_union_map. Takes in a - * FuzzUnionPtr to use within the fuzz_union_map value.*/ -auto GetFuzzStructUnionMapValue(fuzz::mojom::FuzzUnionPtr in) { - decltype(fuzz::mojom::FuzzStruct::fuzz_union_map) union_map; - union_map[fuzz::mojom::FuzzEnum::FUZZ_VALUE1] = std::move(in); - return union_map; -} - -/* Returns a populated value for FuzzStruct->fuzz_union_array. Takes in a - * FuzzUnionPtr to use within the fuzz_union_array value.*/ -auto GetFuzzStructUnionArrayValue(fuzz::mojom::FuzzUnionPtr in) { - decltype(fuzz::mojom::FuzzStruct::fuzz_union_array) union_array; - union_array.push_back(std::move(in)); - return union_array; -} - -/* Returns a populated value for FuzzStruct->fuzz_struct_array. Takes in a - * FuzzStructPtr to use within the fuzz_struct_array value. */ -auto GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStructPtr in) { - decltype(fuzz::mojom::FuzzStruct::fuzz_struct_array) struct_array; - struct_array.push_back(std::move(in)); - return struct_array; -} - -/* Returns a populated value for FuzzStruct->fuzz_nullable_array. */ -auto GetFuzzStructNullableArrayValue() { - decltype(fuzz::mojom::FuzzStruct::fuzz_nullable_array) nullable_array; - return nullable_array; -} - -/* Returns a populated value for FuzzStruct->fuzz_complex. */ -auto GetFuzzStructComplexValue() { - decltype(fuzz::mojom::FuzzStruct::fuzz_complex) complex_map; - std::remove_reference<decltype(complex_map.value()[0])>::type outer; - std::remove_reference<decltype( - outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner; - std::remove_reference<decltype(inner['z'])>::type center; - - center.emplace(); - center.value().push_back(fuzz::mojom::FuzzStruct::New()); - inner['z'] = std::move(center); - outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner); - complex_map.emplace(); - complex_map.value().push_back(std::move(outer)); - return complex_map; -} - -/* Returns a FuzzStruct with its fields populated. */ -fuzz::mojom::FuzzStructPtr GetPopulatedFuzzStruct() { - /* Make some populated Unions. */ - auto union_bool = GetBoolFuzzUnion(); - auto union_struct_map = - GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStruct::New()); - auto union_complex = GetComplexFuzzUnion(std::move(union_bool)); - - /* Prepare the nontrivial fields for the struct. */ - auto fuzz_primitive_array = GetFuzzStructPrimitiveArrayValue(); - auto fuzz_primitive_map = GetFuzzStructPrimitiveMapValue(); - auto fuzz_array_map = GetFuzzStructArrayMapValue(); - auto fuzz_union_map = GetFuzzStructUnionMapValue(std::move(union_struct_map)); - auto fuzz_union_array = - GetFuzzStructUnionArrayValue(std::move(union_complex)); - auto fuzz_struct_array = - GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStruct::New()); - auto fuzz_nullable_array = GetFuzzStructNullableArrayValue(); - auto fuzz_complex = GetFuzzStructComplexValue(); - - /* Make a populated struct and return it. */ - return fuzz::mojom::FuzzStruct::New( - true, /* fuzz_bool */ - -1, /* fuzz_int8 */ - 1, /* fuzz_uint8 */ - -(1 << 8), /* fuzz_int16 */ - 1 << 8, /* fuzz_uint16 */ - -(1 << 16), /* fuzz_int32 */ - 1 << 16, /* fuzz_uint32 */ - -((int64_t)1 << 32), /* fuzz_int64 */ - (uint64_t)1 << 32, /* fuzz_uint64 */ - 1.0, /* fuzz_float */ - 1.0, /* fuzz_double */ - "fuzz", /* fuzz_string */ - std::move(fuzz_primitive_array), /* fuzz_primitive_array */ - std::move(fuzz_primitive_map), /* fuzz_primitive_map */ - std::move(fuzz_array_map), /* fuzz_array_map */ - std::move(fuzz_union_map), /* fuzz_union_map */ - std::move(fuzz_union_array), /* fuzz_union_array */ - std::move(fuzz_struct_array), /* fuzz_struct_array */ - std::move(fuzz_nullable_array), /* fuzz_nullable_array */ - std::move(fuzz_complex)); /* fuzz_complex */ -} - -/* Callback used for messages with responses. Does nothing. */ -void FuzzCallback() {} - -/* Invokes each method in the FuzzInterface and dumps the messages to the - * supplied directory. */ -void DumpMessages(std::string output_directory) { - fuzz::mojom::FuzzInterfacePtr fuzz; - fuzz::mojom::FuzzDummyInterfaceAssociatedPtr dummy; - - /* Create the impl and add a MessageDumper to the filter chain. */ - env->impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - env->impl->binding_.RouterForTesting()->AddIncomingMessageFilter( - std::make_unique<MessageDumper>(output_directory)); - - /* Call methods in various ways to generate interesting messages. */ - fuzz->FuzzBasic(); - fuzz->FuzzBasicResp(base::Bind(FuzzCallback)); - fuzz->FuzzBasicSyncResp(); - fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(), - fuzz::mojom::FuzzStructPtr(nullptr)); - fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct()); - fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(), - base::Bind(FuzzCallback)); - fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(), - base::Bind(FuzzCallback)); - fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(), - GetPopulatedFuzzStruct(), base::Bind(FuzzCallback)); - fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(), - GetPopulatedFuzzStruct(), base::Bind(FuzzCallback)); - fuzz->FuzzAssociated(MakeRequest(&dummy)); - dummy->Ping(); -} - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: %s [output_directory]\n", argv[0]); - exit(1); - } - std::string output_directory(argv[1]); - - /* Dump the messages from a MessageLoop, and wait for it to finish. */ - env->message_loop.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&DumpMessages, output_directory)); - base::RunLoop().RunUntilIdle(); - - return 0; -} diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc deleted file mode 100644 index 28ff521a4ee..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2017 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 "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/task/task_scheduler/task_scheduler.h" -#include "mojo/core/embedder/embedder.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/tools/fuzzers/fuzz_impl.h" - -void FuzzMessage(const uint8_t* data, size_t size, base::RunLoop* run) { - fuzz::mojom::FuzzInterfacePtr fuzz; - auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - auto router = impl->binding_.RouterForTesting(); - - /* Create a mojo message with the appropriate payload size. */ - mojo::Message message(0, 0, size, 0, nullptr); - if (message.data_num_bytes() < size) { - message.payload_buffer()->Allocate(size - message.data_num_bytes()); - } - - /* Set the raw message data. */ - memcpy(message.mutable_data(), data, size); - - /* Run the message through header validation, payload validation, and - * dispatch to the impl. */ - router->SimulateReceivingMessageForTesting(&message); - - /* Allow the harness function to return now. */ - run->Quit(); -} - -/* Environment for the fuzzer. Initializes the mojo EDK and sets up a - * TaskScheduler, because Mojo messages must be sent and processed from - * TaskRunners. */ -struct Environment { - Environment() : message_loop(base::MessageLoop::TYPE_UI) { - base::TaskScheduler::CreateAndStartWithDefaultParams( - "MojoParseMessageFuzzerProcess"); - mojo::core::Init(); - } - - /* Message loop to send and handle messages on. */ - base::MessageLoop message_loop; - - /* Suppress mojo validation failure logs. */ - mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression; -}; - -// Entry point for LibFuzzer. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - static Environment* env = new Environment(); - /* Pass the data along to run on a MessageLoop, and wait for it to finish. */ - base::RunLoop run; - env->message_loop.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&FuzzMessage, data, size, &run)); - run.Run(); - - return 0; -} diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/07775ad8fdb79599024caefbe7889501dfee9e06 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/07775ad8fdb79599024caefbe7889501dfee9e06 deleted file mode 100644 index f1932a62de8..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/07775ad8fdb79599024caefbe7889501dfee9e06 +++ /dev/null @@ -1 +0,0 @@ -messages: "\060\000\000\000\002\000\000\000\000\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\001\000\000\200\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/2ce2f91669a46921ebf4e47679c86dd2bf5b1496 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/2ce2f91669a46921ebf4e47679c86dd2bf5b1496 deleted file mode 100644 index 52bae3dad43..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/2ce2f91669a46921ebf4e47679c86dd2bf5b1496 +++ /dev/null @@ -1 +0,0 @@ -messages: "\030\000\000\000\000\000\000\000\001\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/32a65dcd84debde03d51f8b8ace2cdcc87461d34 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/32a65dcd84debde03d51f8b8ace2cdcc87461d34 deleted file mode 100644 index 9cbd5621d55..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/32a65dcd84debde03d51f8b8ace2cdcc87461d34 +++ /dev/null @@ -1 +0,0 @@ -messages: "\030\000\000\000\000\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\040\001\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\001\377\001\000\000\377\000\001\000\000\377\377\000\000\001\000\000\000\000\000\377\377\377\377\000\000\000\000\001\000\000\000\000\000\200\077\000\000\000\000\000\000\000\000\000\000\360\077\110\000\000\000\000\000\000\000\120\000\000\000\000\000\000\000\130\000\000\000\000\000\000\000\230\000\000\000\000\000\000\000\020\001\000\000\000\000\000\000\240\001\000\000\000\000\000\000\110\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\140\003\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\002\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\015\000\000\000\005\000\000\000\146\165\172\172\061\000\000\000\015\000\000\000\005\000\000\000\146\165\172\172\062\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\001\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\020\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\022\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/7cbf9144ec3980eb121eedc679ebc56a3ddd22a6 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/7cbf9144ec3980eb121eedc679ebc56a3ddd22a6 deleted file mode 100644 index fb4a52b1980..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/7cbf9144ec3980eb121eedc679ebc56a3ddd22a6 +++ /dev/null @@ -1 +0,0 @@ -messages: "\040\000\000\000\001\000\000\000\000\000\000\000\005\000\000\000\001\000\000\000\000\000\000\000\006\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\040\001\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\001\377\001\000\000\377\000\001\000\000\377\377\000\000\001\000\000\000\000\000\377\377\377\377\000\000\000\000\001\000\000\000\000\000\200\077\000\000\000\000\000\000\000\000\000\000\360\077\110\000\000\000\000\000\000\000\120\000\000\000\000\000\000\000\130\000\000\000\000\000\000\000\230\000\000\000\000\000\000\000\020\001\000\000\000\000\000\000\240\001\000\000\000\000\000\000\110\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\140\003\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\002\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\015\000\000\000\005\000\000\000\146\165\172\172\061\000\000\000\015\000\000\000\005\000\000\000\146\165\172\172\062\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\001\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\020\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\050\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\014\000\000\000\004\000\000\000\146\165\172\172\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\022\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\001\000\000\000\020\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\014\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\011\000\000\000\001\000\000\000\172\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\020\000\000\000\001\000\000\000\010\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9ccc6b5c0a61672816dc252194c3d722c18107bc b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9ccc6b5c0a61672816dc252194c3d722c18107bc deleted file mode 100644 index d5fa6119789..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9ccc6b5c0a61672816dc252194c3d722c18107bc +++ /dev/null @@ -1 +0,0 @@ -messages: "\040\000\000\000\001\000\000\000\000\000\000\000\002\000\000\000\005\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9e0a62bdd4b08cb777bee9449a22b3ad6702b106 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9e0a62bdd4b08cb777bee9449a22b3ad6702b106 deleted file mode 100644 index c5567f2f49b..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/9e0a62bdd4b08cb777bee9449a22b3ad6702b106 +++ /dev/null @@ -1 +0,0 @@ -messages: "\030\000\000\000\000\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\110\000\000\000\000\000\000\000\150\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/a74241101f97704b96c9ba11b4781651e236ad8f b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/a74241101f97704b96c9ba11b4781651e236ad8f deleted file mode 100644 index 619a2bbe143..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/a74241101f97704b96c9ba11b4781651e236ad8f +++ /dev/null @@ -1 +0,0 @@ -messages: "\030\000\000\000\000\000\000\000\377\377\377\377\376\377\377\377\000\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\030\000\000\000\000\000\000\000\001\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/be66c5d078fbf574388b7b1d25a29ff2d16df67e b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/be66c5d078fbf574388b7b1d25a29ff2d16df67e deleted file mode 100644 index dcd7e6e8c1b..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/be66c5d078fbf574388b7b1d25a29ff2d16df67e +++ /dev/null @@ -1 +0,0 @@ -messages: "\040\000\000\000\001\000\000\000\000\000\000\000\001\000\000\000\001\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/e4be6bde72d04c5cda7d4939a80e5890c5c01374 b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/e4be6bde72d04c5cda7d4939a80e5890c5c01374 deleted file mode 100644 index 186f82d8676..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_corpus/e4be6bde72d04c5cda7d4939a80e5890c5c01374 +++ /dev/null @@ -1 +0,0 @@ -messages: "\030\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000" diff --git a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc b/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc deleted file mode 100644 index d6b5e9684cd..00000000000 --- a/chromium/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc +++ /dev/null @@ -1,71 +0,0 @@ -// 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. - -// Implementation of a proto version of mojo_parse_message_fuzzer that sends -// multiple messages per run. - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/task/task_scheduler/task_scheduler.h" -#include "mojo/core/embedder/embedder.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/tools/fuzzers/fuzz_impl.h" -#include "mojo/public/tools/fuzzers/mojo_fuzzer.pb.h" -#include "testing/libfuzzer/proto/lpm_interface.h" - -namespace mojo_proto_fuzzer { - -void FuzzMessage(const MojoFuzzerMessages& mojo_fuzzer_messages, - base::RunLoop* run) { - fuzz::mojom::FuzzInterfacePtr fuzz; - auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz)); - auto router = impl->binding_.RouterForTesting(); - - for (auto& message_str : mojo_fuzzer_messages.messages()) { - // Create a mojo message with the appropriate payload size. - mojo::Message message(0, 0, message_str.size(), 0, nullptr); - if (message.data_num_bytes() < message_str.size()) { - message.payload_buffer()->Allocate(message_str.size() - - message.data_num_bytes()); - } - - // Set the raw message data. - memcpy(message.mutable_data(), message_str.data(), message_str.size()); - - // Run the message through header validation, payload validation, and - // dispatch to the impl. - router->SimulateReceivingMessageForTesting(&message); - } - - // Allow the harness function to return now. - run->Quit(); -} - -// Environment for the fuzzer. Initializes the mojo EDK and sets up a -// TaskScheduler, because Mojo messages must be sent and processed from -// TaskRunners. -struct Environment { - Environment() : message_loop(base::MessageLoop::TYPE_UI) { - base::TaskScheduler::CreateAndStartWithDefaultParams( - "MojoParseMessageFuzzerProcess"); - mojo::core::Init(); - } - - // Message loop to send and handle messages on. - base::MessageLoop message_loop; - - // Suppress mojo validation failure logs. - mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression; -}; - -DEFINE_PROTO_FUZZER(const MojoFuzzerMessages& mojo_fuzzer_messages) { - static Environment* env = new Environment(); - // Pass the data along to run on a MessageLoop, and wait for it to finish. - base::RunLoop run; - env->message_loop.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&FuzzMessage, mojo_fuzzer_messages, &run)); - run.Run(); -} -} // namespace mojo_proto_fuzzer |