| // 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 "mojo/core/user_message_impl.h" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "base/atomicops.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros_local.h" |
| #include "base/no_destructor.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/numerics/safe_math.h" |
| #include "base/trace_event/memory_allocator_dump.h" |
| #include "base/trace_event/memory_dump_manager.h" |
| #include "base/trace_event/memory_dump_provider.h" |
| #include "base/trace_event/trace_event.h" |
| #include "mojo/core/core.h" |
| #include "mojo/core/node_channel.h" |
| #include "mojo/core/node_controller.h" |
| #include "mojo/core/ports/event.h" |
| #include "mojo/core/ports/message_filter.h" |
| #include "mojo/core/ports/node.h" |
| #include "mojo/public/c/system/types.h" |
| |
| namespace mojo { |
| namespace core { |
| |
| namespace { |
| |
| // The minimum amount of memory to allocate for a new serialized message buffer. |
| // This should be sufficiently large such that most seiralized messages do not |
| // incur any reallocations as they're expanded to full size. |
| const uint32_t kMinimumPayloadBufferSize = 128; |
| |
| // The maximum number of Mojo handles which can be attached to a serialized |
| // user message. Much larger than should ever be necessary, but small enough |
| // to not be a problem. |
| const uint32_t kMaxMojoHandleAttachments = 1024 * 1024; |
| |
| // Indicates whether handle serialization failure should be emulated in testing. |
| bool g_always_fail_handle_serialization = false; |
| |
| #pragma pack(push, 1) |
| // Header attached to every message. |
| struct MessageHeader { |
| // The number of serialized dispatchers included in this header. |
| uint32_t num_dispatchers; |
| |
| // Total size of the header, including serialized dispatcher data. |
| uint32_t header_size; |
| }; |
| |
| // Header for each dispatcher in a message, immediately following the message |
| // header. |
| struct DispatcherHeader { |
| // The type of the dispatcher, correpsonding to the Dispatcher::Type enum. |
| int32_t type; |
| |
| // The size of the serialized dispatcher, not including this header. |
| uint32_t num_bytes; |
| |
| // The number of ports needed to deserialize this dispatcher. |
| uint32_t num_ports; |
| |
| // The number of platform handles needed to deserialize this dispatcher. |
| uint32_t num_platform_handles; |
| }; |
| #pragma pack(pop) |
| |
| static_assert(sizeof(MessageHeader) % 8 == 0, "Invalid MessageHeader size."); |
| static_assert(sizeof(DispatcherHeader) % 8 == 0, |
| "Invalid DispatcherHeader size."); |
| |
| // Creates a new Channel message with sufficient storage for |num_bytes| user |
| // message payload and all |dispatchers| given. If |original_message| is not |
| // null, its contents are copied and extended by the other parameters given |
| // here. |
| MojoResult CreateOrExtendSerializedEventMessage( |
| ports::UserMessageEvent* event, |
| size_t payload_size, |
| size_t payload_buffer_size, |
| const Dispatcher::DispatcherInTransit* new_dispatchers, |
| size_t num_new_dispatchers, |
| Channel::MessagePtr* out_message, |
| void** out_header, |
| size_t* out_header_size, |
| void** out_user_payload) { |
| // A structure for tracking information about every Dispatcher that will be |
| // serialized into the message. This is NOT part of the message itself. |
| struct DispatcherInfo { |
| uint32_t num_bytes; |
| uint32_t num_ports; |
| uint32_t num_handles; |
| }; |
| |
| size_t original_header_size = sizeof(MessageHeader); |
| size_t original_num_ports = 0; |
| size_t original_num_handles = 0; |
| size_t original_payload_size = 0; |
| MessageHeader* original_header = nullptr; |
| void* original_user_payload = nullptr; |
| Channel::MessagePtr original_message; |
| if (*out_message) { |
| original_message = std::move(*out_message); |
| original_header = static_cast<MessageHeader*>(*out_header); |
| original_header_size = *out_header_size; |
| original_num_ports = event->num_ports(); |
| original_num_handles = original_message->num_handles(); |
| original_user_payload = *out_user_payload; |
| original_payload_size = |
| original_message->payload_size() - |
| (static_cast<char*>(original_user_payload) - |
| static_cast<char*>(original_message->mutable_payload())); |
| } |
| |
| // This is only the base header size. It will grow as we accumulate the |
| // size of serialized state for each dispatcher. |
| base::CheckedNumeric<size_t> safe_header_size = num_new_dispatchers; |
| safe_header_size *= sizeof(DispatcherHeader); |
| safe_header_size += original_header_size; |
| size_t header_size = safe_header_size.ValueOrDie(); |
| size_t num_new_ports = 0; |
| size_t num_new_handles = 0; |
| std::vector<DispatcherInfo> new_dispatcher_info(num_new_dispatchers); |
| for (size_t i = 0; i < num_new_dispatchers; ++i) { |
| Dispatcher* d = new_dispatchers[i].dispatcher.get(); |
| d->StartSerialize(&new_dispatcher_info[i].num_bytes, |
| &new_dispatcher_info[i].num_ports, |
| &new_dispatcher_info[i].num_handles); |
| header_size += new_dispatcher_info[i].num_bytes; |
| num_new_ports += new_dispatcher_info[i].num_ports; |
| num_new_handles += new_dispatcher_info[i].num_handles; |
| } |
| |
| size_t num_ports = original_num_ports + num_new_ports; |
| size_t num_handles = original_num_handles + num_new_handles; |
| |
| // We now have enough information to fully allocate the message storage. |
| if (num_ports > event->num_ports()) |
| event->ReservePorts(num_ports); |
| const size_t event_size = event->GetSerializedSize(); |
| const size_t total_size = event_size + header_size + payload_size; |
| const size_t total_buffer_size = |
| event_size + header_size + payload_buffer_size; |
| void* data; |
| Channel::MessagePtr message = NodeChannel::CreateEventMessage( |
| total_buffer_size, total_size, &data, num_handles); |
| auto* header = reinterpret_cast<MessageHeader*>(static_cast<uint8_t*>(data) + |
| event_size); |
| |
| // Populate the message header with information about serialized dispatchers. |
| // The front of the message is always a MessageHeader followed by a |
| // DispatcherHeader for each dispatcher to be sent. |
| DispatcherHeader* new_dispatcher_headers; |
| char* new_dispatcher_data; |
| size_t total_num_dispatchers = num_new_dispatchers; |
| std::vector<PlatformHandle> handles; |
| if (original_message) { |
| DCHECK(original_header); |
| size_t original_dispatcher_headers_size = |
| original_header->num_dispatchers * sizeof(DispatcherHeader); |
| memcpy(header, original_header, |
| original_dispatcher_headers_size + sizeof(MessageHeader)); |
| new_dispatcher_headers = reinterpret_cast<DispatcherHeader*>( |
| reinterpret_cast<uint8_t*>(header + 1) + |
| original_dispatcher_headers_size); |
| total_num_dispatchers += original_header->num_dispatchers; |
| size_t total_dispatcher_headers_size = |
| total_num_dispatchers * sizeof(DispatcherHeader); |
| char* original_dispatcher_data = |
| reinterpret_cast<char*>(original_header + 1) + |
| original_dispatcher_headers_size; |
| char* dispatcher_data = |
| reinterpret_cast<char*>(header + 1) + total_dispatcher_headers_size; |
| size_t original_dispatcher_data_size = original_header_size - |
| sizeof(MessageHeader) - |
| original_dispatcher_headers_size; |
| memcpy(dispatcher_data, original_dispatcher_data, |
| original_dispatcher_data_size); |
| new_dispatcher_data = dispatcher_data + original_dispatcher_data_size; |
| auto handles_in_transit = original_message->TakeHandles(); |
| if (!handles_in_transit.empty()) { |
| handles.resize(num_handles); |
| for (size_t i = 0; i < handles_in_transit.size(); ++i) |
| handles[i] = handles_in_transit[i].TakeHandle(); |
| } |
| memcpy(reinterpret_cast<char*>(header) + header_size, |
| reinterpret_cast<char*>(original_header) + original_header_size, |
| original_payload_size); |
| } else { |
| new_dispatcher_headers = reinterpret_cast<DispatcherHeader*>(header + 1); |
| // Serialized dispatcher state immediately follows the series of |
| // DispatcherHeaders. |
| new_dispatcher_data = |
| reinterpret_cast<char*>(new_dispatcher_headers + num_new_dispatchers); |
| } |
| |
| if (handles.empty() && num_new_handles) |
| handles.resize(num_new_handles); |
| |
| header->num_dispatchers = |
| base::CheckedNumeric<uint32_t>(total_num_dispatchers).ValueOrDie(); |
| |
| // |header_size| is the total number of bytes preceding the message payload, |
| // including all dispatcher headers and serialized dispatcher state. |
| if (!base::IsValueInRangeForNumericType<uint32_t>(header_size)) |
| return MOJO_RESULT_OUT_OF_RANGE; |
| |
| header->header_size = static_cast<uint32_t>(header_size); |
| |
| if (num_new_dispatchers > 0) { |
| size_t port_index = original_num_ports; |
| size_t handle_index = original_num_handles; |
| bool fail = false; |
| for (size_t i = 0; i < num_new_dispatchers; ++i) { |
| Dispatcher* d = new_dispatchers[i].dispatcher.get(); |
| DispatcherHeader* dh = &new_dispatcher_headers[i]; |
| const DispatcherInfo& info = new_dispatcher_info[i]; |
| |
| // Fill in the header for this dispatcher. |
| dh->type = static_cast<int32_t>(d->GetType()); |
| dh->num_bytes = info.num_bytes; |
| dh->num_ports = info.num_ports; |
| dh->num_platform_handles = info.num_handles; |
| |
| // Fill in serialized state, ports, and platform handles. We'll cancel |
| // the send if the dispatcher implementation rejects for some reason. |
| if (g_always_fail_handle_serialization || |
| !d->EndSerialize( |
| static_cast<void*>(new_dispatcher_data), |
| event->ports() + port_index, |
| !handles.empty() ? handles.data() + handle_index : nullptr)) { |
| fail = true; |
| break; |
| } |
| |
| new_dispatcher_data += info.num_bytes; |
| port_index += info.num_ports; |
| handle_index += info.num_handles; |
| } |
| |
| if (fail) { |
| // Release any platform handles we've accumulated. Their dispatchers |
| // retain ownership when message creation fails, so these are not actually |
| // leaking. |
| for (auto& handle : handles) |
| handle.release(); |
| |
| // Leave the original message in place on failure if applicable. |
| if (original_message) |
| *out_message = std::move(original_message); |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| } |
| |
| // Take ownership of all the handles and move them into message storage. |
| message->SetHandles(std::move(handles)); |
| } |
| |
| *out_message = std::move(message); |
| *out_header = header; |
| *out_header_size = header_size; |
| *out_user_payload = reinterpret_cast<uint8_t*>(header) + header_size; |
| return MOJO_RESULT_OK; |
| } |
| |
| base::subtle::Atomic32 g_message_count = 0; |
| |
| void IncrementMessageCount() { |
| base::subtle::NoBarrier_AtomicIncrement(&g_message_count, 1); |
| } |
| |
| void DecrementMessageCount() { |
| base::subtle::NoBarrier_AtomicIncrement(&g_message_count, -1); |
| } |
| |
| class MessageMemoryDumpProvider : public base::trace_event::MemoryDumpProvider { |
| public: |
| MessageMemoryDumpProvider() { |
| base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| this, "MojoMessages", nullptr); |
| } |
| |
| ~MessageMemoryDumpProvider() override { |
| base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
| this); |
| } |
| |
| private: |
| // base::trace_event::MemoryDumpProvider: |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) override { |
| auto* dump = pmd->CreateAllocatorDump("mojo/messages"); |
| dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount, |
| base::trace_event::MemoryAllocatorDump::kUnitsObjects, |
| base::subtle::NoBarrier_Load(&g_message_count)); |
| return true; |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(MessageMemoryDumpProvider); |
| }; |
| |
| void EnsureMemoryDumpProviderExists() { |
| static base::NoDestructor<MessageMemoryDumpProvider> provider; |
| ALLOW_UNUSED_LOCAL(provider); |
| } |
| |
| } // namespace |
| |
| // static |
| const ports::UserMessage::TypeInfo UserMessageImpl::kUserMessageTypeInfo = {}; |
| |
| UserMessageImpl::~UserMessageImpl() { |
| if (HasContext() && context_destructor_) { |
| DCHECK(!channel_message_); |
| DCHECK(!has_serialized_handles_); |
| context_destructor_(context_); |
| } else if (IsSerialized() && has_serialized_handles_) { |
| // Ensure that any handles still serialized within this message are |
| // extracted and closed so they don't leak. |
| std::vector<MojoHandle> handles(num_handles()); |
| MojoResult result = |
| ExtractSerializedHandles(ExtractBadHandlePolicy::kSkip, handles.data()); |
| if (result == MOJO_RESULT_OK) { |
| for (auto handle : handles) { |
| if (handle != MOJO_HANDLE_INVALID) |
| Core::Get()->Close(handle); |
| } |
| } |
| |
| if (!pending_handle_attachments_.empty()) { |
| Core::Get()->ReleaseDispatchersForTransit(pending_handle_attachments_, |
| false); |
| for (const auto& dispatcher : pending_handle_attachments_) |
| Core::Get()->Close(dispatcher.local_handle); |
| } |
| } |
| |
| DecrementMessageCount(); |
| } |
| |
| // static |
| std::unique_ptr<ports::UserMessageEvent> |
| UserMessageImpl::CreateEventForNewMessage() { |
| auto message_event = std::make_unique<ports::UserMessageEvent>(0); |
| message_event->AttachMessage( |
| base::WrapUnique(new UserMessageImpl(message_event.get()))); |
| return message_event; |
| } |
| |
| // static |
| MojoResult UserMessageImpl::CreateEventForNewSerializedMessage( |
| uint32_t num_bytes, |
| const Dispatcher::DispatcherInTransit* dispatchers, |
| uint32_t num_dispatchers, |
| std::unique_ptr<ports::UserMessageEvent>* out_event) { |
| Channel::MessagePtr channel_message; |
| void* header = nullptr; |
| void* user_payload = nullptr; |
| auto event = std::make_unique<ports::UserMessageEvent>(0); |
| size_t header_size = 0; |
| MojoResult rv = CreateOrExtendSerializedEventMessage( |
| event.get(), num_bytes, num_bytes, dispatchers, num_dispatchers, |
| &channel_message, &header, &header_size, &user_payload); |
| if (rv != MOJO_RESULT_OK) |
| return rv; |
| event->AttachMessage(base::WrapUnique( |
| new UserMessageImpl(event.get(), std::move(channel_message), header, |
| header_size, user_payload, num_bytes))); |
| *out_event = std::move(event); |
| return MOJO_RESULT_OK; |
| } |
| |
| // static |
| std::unique_ptr<UserMessageImpl> UserMessageImpl::CreateFromChannelMessage( |
| ports::UserMessageEvent* message_event, |
| Channel::MessagePtr channel_message, |
| void* payload, |
| size_t payload_size) { |
| DCHECK(channel_message); |
| if (payload_size < sizeof(MessageHeader)) |
| return nullptr; |
| |
| auto* header = static_cast<MessageHeader*>(payload); |
| const size_t header_size = header->header_size; |
| if (header_size > payload_size) |
| return nullptr; |
| |
| if (header->num_dispatchers > kMaxMojoHandleAttachments) |
| return nullptr; |
| |
| void* user_payload = static_cast<uint8_t*>(payload) + header_size; |
| const size_t user_payload_size = payload_size - header_size; |
| return base::WrapUnique( |
| new UserMessageImpl(message_event, std::move(channel_message), header, |
| header_size, user_payload, user_payload_size)); |
| } |
| |
| // static |
| Channel::MessagePtr UserMessageImpl::FinalizeEventMessage( |
| std::unique_ptr<ports::UserMessageEvent> message_event) { |
| auto* message = message_event->GetMessage<UserMessageImpl>(); |
| DCHECK(message->IsSerialized()); |
| |
| if (!message->is_committed_) |
| return nullptr; |
| |
| Channel::MessagePtr channel_message = std::move(message->channel_message_); |
| message->user_payload_ = nullptr; |
| message->user_payload_size_ = 0; |
| |
| // Serialize the UserMessageEvent into the front of the message payload where |
| // there is already space reserved for it. |
| if (channel_message) { |
| void* data; |
| size_t size; |
| NodeChannel::GetEventMessageData(channel_message.get(), &data, &size); |
| message_event->Serialize(data); |
| } |
| |
| return channel_message; |
| } |
| |
| size_t UserMessageImpl::user_payload_capacity() const { |
| DCHECK(IsSerialized()); |
| const size_t user_payload_offset = |
| static_cast<uint8_t*>(user_payload_) - |
| static_cast<const uint8_t*>(channel_message_->payload()); |
| const size_t message_capacity = channel_message_->capacity(); |
| DCHECK_LE(user_payload_offset, message_capacity); |
| return message_capacity - user_payload_offset; |
| } |
| |
| size_t UserMessageImpl::num_handles() const { |
| DCHECK(IsSerialized()); |
| DCHECK(header_); |
| return static_cast<const MessageHeader*>(header_)->num_dispatchers; |
| } |
| |
| MojoResult UserMessageImpl::SetContext( |
| uintptr_t context, |
| MojoMessageContextSerializer serializer, |
| MojoMessageContextDestructor destructor) { |
| if (!context && (serializer || destructor)) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| if (context && HasContext()) |
| return MOJO_RESULT_ALREADY_EXISTS; |
| if (IsSerialized()) |
| return MOJO_RESULT_FAILED_PRECONDITION; |
| context_ = context; |
| context_serializer_ = serializer; |
| context_destructor_ = destructor; |
| return MOJO_RESULT_OK; |
| } |
| |
| MojoResult UserMessageImpl::AppendData(uint32_t additional_payload_size, |
| const MojoHandle* handles, |
| uint32_t num_handles) { |
| if (HasContext()) |
| return MOJO_RESULT_FAILED_PRECONDITION; |
| |
| std::vector<Dispatcher::DispatcherInTransit> dispatchers; |
| if (num_handles > 0) { |
| MojoResult acquire_result = Core::Get()->AcquireDispatchersForTransit( |
| handles, num_handles, &dispatchers); |
| if (acquire_result != MOJO_RESULT_OK) |
| return acquire_result; |
| } |
| |
| if (!IsSerialized()) { |
| // First data for this message. |
| Channel::MessagePtr channel_message; |
| MojoResult rv = CreateOrExtendSerializedEventMessage( |
| message_event_, additional_payload_size, |
| std::max(additional_payload_size, kMinimumPayloadBufferSize), |
| dispatchers.data(), num_handles, &channel_message, &header_, |
| &header_size_, &user_payload_); |
| if (num_handles > 0) { |
| Core::Get()->ReleaseDispatchersForTransit(dispatchers, |
| rv == MOJO_RESULT_OK); |
| } |
| if (rv != MOJO_RESULT_OK) |
| return MOJO_RESULT_ABORTED; |
| |
| user_payload_size_ = additional_payload_size; |
| channel_message_ = std::move(channel_message); |
| has_serialized_handles_ = true; |
| } else { |
| // Extend the existing message payload. |
| |
| // In order to avoid rather expensive message resizing on every handle |
| // attachment operation, we merely lock and prepare the handle for transit |
| // here, deferring serialization until |CommitSize()|. |
| std::copy(dispatchers.begin(), dispatchers.end(), |
| std::back_inserter(pending_handle_attachments_)); |
| |
| if (additional_payload_size) { |
| size_t header_offset = |
| static_cast<uint8_t*>(header_) - |
| static_cast<const uint8_t*>(channel_message_->payload()); |
| size_t user_payload_offset = |
| static_cast<uint8_t*>(user_payload_) - |
| static_cast<const uint8_t*>(channel_message_->payload()); |
| channel_message_->ExtendPayload(user_payload_offset + user_payload_size_ + |
| additional_payload_size); |
| header_ = static_cast<uint8_t*>(channel_message_->mutable_payload()) + |
| header_offset; |
| user_payload_ = |
| static_cast<uint8_t*>(channel_message_->mutable_payload()) + |
| user_payload_offset; |
| user_payload_size_ += additional_payload_size; |
| } |
| } |
| |
| return MOJO_RESULT_OK; |
| } |
| |
| MojoResult UserMessageImpl::CommitSize() { |
| if (!IsSerialized()) |
| return MOJO_RESULT_FAILED_PRECONDITION; |
| |
| if (is_committed_) |
| return MOJO_RESULT_OK; |
| |
| if (!pending_handle_attachments_.empty()) { |
| CreateOrExtendSerializedEventMessage( |
| message_event_, user_payload_size_, user_payload_size_, |
| pending_handle_attachments_.data(), pending_handle_attachments_.size(), |
| &channel_message_, &header_, &header_size_, &user_payload_); |
| Core::Get()->ReleaseDispatchersForTransit(pending_handle_attachments_, |
| true); |
| pending_handle_attachments_.clear(); |
| } |
| |
| is_committed_ = true; |
| return MOJO_RESULT_OK; |
| } |
| |
| MojoResult UserMessageImpl::SerializeIfNecessary() { |
| if (IsSerialized()) |
| return MOJO_RESULT_FAILED_PRECONDITION; |
| |
| DCHECK(HasContext()); |
| DCHECK(!has_serialized_handles_); |
| if (!context_serializer_) |
| return MOJO_RESULT_NOT_FOUND; |
| |
| uintptr_t context = context_; |
| context_ = 0; |
| context_serializer_(reinterpret_cast<MojoMessageHandle>(message_event_), |
| context); |
| |
| if (context_destructor_) |
| context_destructor_(context); |
| |
| has_serialized_handles_ = true; |
| return MOJO_RESULT_OK; |
| } |
| |
| MojoResult UserMessageImpl::ExtractSerializedHandles( |
| ExtractBadHandlePolicy bad_handle_policy, |
| MojoHandle* handles) { |
| if (!IsSerialized()) |
| return MOJO_RESULT_FAILED_PRECONDITION; |
| |
| if (!has_serialized_handles_) |
| return MOJO_RESULT_NOT_FOUND; |
| |
| const MessageHeader* header = static_cast<const MessageHeader*>(header_); |
| const DispatcherHeader* dispatcher_headers = |
| reinterpret_cast<const DispatcherHeader*>(header + 1); |
| |
| if (header->num_dispatchers > std::numeric_limits<uint16_t>::max()) |
| return MOJO_RESULT_ABORTED; |
| |
| if (header->num_dispatchers == 0) |
| return MOJO_RESULT_OK; |
| |
| has_serialized_handles_ = false; |
| |
| std::vector<Dispatcher::DispatcherInTransit> dispatchers( |
| header->num_dispatchers); |
| |
| size_t data_payload_index = |
| sizeof(MessageHeader) + |
| header->num_dispatchers * sizeof(DispatcherHeader); |
| if (data_payload_index > header->header_size) |
| return MOJO_RESULT_ABORTED; |
| const char* dispatcher_data = reinterpret_cast<const char*>( |
| dispatcher_headers + header->num_dispatchers); |
| size_t port_index = 0; |
| size_t platform_handle_index = 0; |
| std::vector<PlatformHandleInTransit> handles_in_transit = |
| channel_message_->TakeHandles(); |
| std::vector<PlatformHandle> msg_handles(handles_in_transit.size()); |
| for (size_t i = 0; i < handles_in_transit.size(); ++i) { |
| DCHECK(!handles_in_transit[i].owning_process().is_valid()); |
| msg_handles[i] = handles_in_transit[i].TakeHandle(); |
| } |
| for (size_t i = 0; i < header->num_dispatchers; ++i) { |
| const DispatcherHeader& dh = dispatcher_headers[i]; |
| auto type = static_cast<Dispatcher::Type>(dh.type); |
| |
| base::CheckedNumeric<size_t> next_payload_index = data_payload_index; |
| next_payload_index += dh.num_bytes; |
| if (!next_payload_index.IsValid() || |
| header->header_size < next_payload_index.ValueOrDie()) { |
| return MOJO_RESULT_ABORTED; |
| } |
| |
| base::CheckedNumeric<size_t> next_port_index = port_index; |
| next_port_index += dh.num_ports; |
| if (!next_port_index.IsValid() || |
| message_event_->num_ports() < next_port_index.ValueOrDie()) { |
| return MOJO_RESULT_ABORTED; |
| } |
| |
| base::CheckedNumeric<size_t> next_platform_handle_index = |
| platform_handle_index; |
| next_platform_handle_index += dh.num_platform_handles; |
| if (!next_platform_handle_index.IsValid() || |
| msg_handles.size() < next_platform_handle_index.ValueOrDie()) { |
| return MOJO_RESULT_ABORTED; |
| } |
| |
| PlatformHandle* out_handles = |
| !msg_handles.empty() ? msg_handles.data() + platform_handle_index |
| : nullptr; |
| dispatchers[i].dispatcher = Dispatcher::Deserialize( |
| type, dispatcher_data, dh.num_bytes, |
| message_event_->ports() + port_index, dh.num_ports, out_handles, |
| dh.num_platform_handles); |
| if (!dispatchers[i].dispatcher && |
| bad_handle_policy == ExtractBadHandlePolicy::kAbort) { |
| return MOJO_RESULT_ABORTED; |
| } |
| |
| dispatcher_data += dh.num_bytes; |
| data_payload_index = next_payload_index.ValueOrDie(); |
| port_index = next_port_index.ValueOrDie(); |
| platform_handle_index = next_platform_handle_index.ValueOrDie(); |
| } |
| |
| if (!Core::Get()->AddDispatchersFromTransit(dispatchers, handles)) |
| return MOJO_RESULT_ABORTED; |
| |
| return MOJO_RESULT_OK; |
| } |
| |
| // static |
| void UserMessageImpl::FailHandleSerializationForTesting(bool fail) { |
| g_always_fail_handle_serialization = fail; |
| } |
| |
| UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event) |
| : ports::UserMessage(&kUserMessageTypeInfo), message_event_(message_event) { |
| EnsureMemoryDumpProviderExists(); |
| IncrementMessageCount(); |
| } |
| |
| UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event, |
| Channel::MessagePtr channel_message, |
| void* header, |
| size_t header_size, |
| void* user_payload, |
| size_t user_payload_size) |
| : ports::UserMessage(&kUserMessageTypeInfo), |
| message_event_(message_event), |
| channel_message_(std::move(channel_message)), |
| has_serialized_handles_(true), |
| is_committed_(true), |
| header_(header), |
| header_size_(header_size), |
| user_payload_(user_payload), |
| user_payload_size_(user_payload_size) { |
| EnsureMemoryDumpProviderExists(); |
| IncrementMessageCount(); |
| } |
| |
| bool UserMessageImpl::WillBeRoutedExternally() { |
| MojoResult result = SerializeIfNecessary(); |
| return result == MOJO_RESULT_OK || result == MOJO_RESULT_FAILED_PRECONDITION; |
| } |
| |
| size_t UserMessageImpl::GetSizeIfSerialized() const { |
| if (!IsSerialized()) |
| return 0; |
| return user_payload_size_; |
| } |
| |
| } // namespace core |
| } // namespace mojo |