Home | History | Annotate | Download | only in core
      1 // Copyright 2017 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/core/user_message_impl.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/atomicops.h"
     11 #include "base/memory/ptr_util.h"
     12 #include "base/metrics/histogram_macros_local.h"
     13 #include "base/no_destructor.h"
     14 #include "base/numerics/safe_conversions.h"
     15 #include "base/numerics/safe_math.h"
     16 // #include "base/trace_event/memory_allocator_dump.h"
     17 // #include "base/trace_event/memory_dump_manager.h"
     18 // #include "base/trace_event/memory_dump_provider.h"
     19 // #include "base/trace_event/trace_event.h"
     20 #include "mojo/core/core.h"
     21 #include "mojo/core/node_channel.h"
     22 #include "mojo/core/node_controller.h"
     23 #include "mojo/core/ports/event.h"
     24 #include "mojo/core/ports/message_filter.h"
     25 #include "mojo/core/ports/node.h"
     26 #include "mojo/public/c/system/types.h"
     27 
     28 namespace mojo {
     29 namespace core {
     30 
     31 namespace {
     32 
     33 // The minimum amount of memory to allocate for a new serialized message buffer.
     34 // This should be sufficiently large such that most seiralized messages do not
     35 // incur any reallocations as they're expanded to full size.
     36 const uint32_t kMinimumPayloadBufferSize = 128;
     37 
     38 // Indicates whether handle serialization failure should be emulated in testing.
     39 bool g_always_fail_handle_serialization = false;
     40 
     41 #pragma pack(push, 1)
     42 // Header attached to every message.
     43 struct MessageHeader {
     44   // The number of serialized dispatchers included in this header.
     45   uint32_t num_dispatchers;
     46 
     47   // Total size of the header, including serialized dispatcher data.
     48   uint32_t header_size;
     49 };
     50 
     51 // Header for each dispatcher in a message, immediately following the message
     52 // header.
     53 struct DispatcherHeader {
     54   // The type of the dispatcher, correpsonding to the Dispatcher::Type enum.
     55   int32_t type;
     56 
     57   // The size of the serialized dispatcher, not including this header.
     58   uint32_t num_bytes;
     59 
     60   // The number of ports needed to deserialize this dispatcher.
     61   uint32_t num_ports;
     62 
     63   // The number of platform handles needed to deserialize this dispatcher.
     64   uint32_t num_platform_handles;
     65 };
     66 #pragma pack(pop)
     67 
     68 static_assert(sizeof(MessageHeader) % 8 == 0, "Invalid MessageHeader size.");
     69 static_assert(sizeof(DispatcherHeader) % 8 == 0,
     70               "Invalid DispatcherHeader size.");
     71 
     72 // Creates a new Channel message with sufficient storage for |num_bytes| user
     73 // message payload and all |dispatchers| given. If |original_message| is not
     74 // null, its contents are copied and extended by the other parameters given
     75 // here.
     76 MojoResult CreateOrExtendSerializedEventMessage(
     77     ports::UserMessageEvent* event,
     78     size_t payload_size,
     79     size_t payload_buffer_size,
     80     const Dispatcher::DispatcherInTransit* new_dispatchers,
     81     size_t num_new_dispatchers,
     82     Channel::MessagePtr* out_message,
     83     void** out_header,
     84     size_t* out_header_size,
     85     void** out_user_payload) {
     86   // A structure for tracking information about every Dispatcher that will be
     87   // serialized into the message. This is NOT part of the message itself.
     88   struct DispatcherInfo {
     89     uint32_t num_bytes;
     90     uint32_t num_ports;
     91     uint32_t num_handles;
     92   };
     93 
     94   size_t original_header_size = sizeof(MessageHeader);
     95   size_t original_num_ports = 0;
     96   size_t original_num_handles = 0;
     97   size_t original_payload_size = 0;
     98   MessageHeader* original_header = nullptr;
     99   void* original_user_payload = nullptr;
    100   Channel::MessagePtr original_message;
    101   if (*out_message) {
    102     original_message = std::move(*out_message);
    103     original_header = static_cast<MessageHeader*>(*out_header);
    104     original_header_size = *out_header_size;
    105     original_num_ports = event->num_ports();
    106     original_num_handles = original_message->num_handles();
    107     original_user_payload = *out_user_payload;
    108     original_payload_size =
    109         original_message->payload_size() -
    110         (static_cast<char*>(original_user_payload) -
    111          static_cast<char*>(original_message->mutable_payload()));
    112   }
    113 
    114   // This is only the base header size. It will grow as we accumulate the
    115   // size of serialized state for each dispatcher.
    116   base::CheckedNumeric<size_t> safe_header_size = num_new_dispatchers;
    117   safe_header_size *= sizeof(DispatcherHeader);
    118   safe_header_size += original_header_size;
    119   size_t header_size = safe_header_size.ValueOrDie();
    120   size_t num_new_ports = 0;
    121   size_t num_new_handles = 0;
    122   std::vector<DispatcherInfo> new_dispatcher_info(num_new_dispatchers);
    123   for (size_t i = 0; i < num_new_dispatchers; ++i) {
    124     Dispatcher* d = new_dispatchers[i].dispatcher.get();
    125     d->StartSerialize(&new_dispatcher_info[i].num_bytes,
    126                       &new_dispatcher_info[i].num_ports,
    127                       &new_dispatcher_info[i].num_handles);
    128     header_size += new_dispatcher_info[i].num_bytes;
    129     num_new_ports += new_dispatcher_info[i].num_ports;
    130     num_new_handles += new_dispatcher_info[i].num_handles;
    131   }
    132 
    133   size_t num_ports = original_num_ports + num_new_ports;
    134   size_t num_handles = original_num_handles + num_new_handles;
    135 
    136   // We now have enough information to fully allocate the message storage.
    137   if (num_ports > event->num_ports())
    138     event->ReservePorts(num_ports);
    139   const size_t event_size = event->GetSerializedSize();
    140   const size_t total_size = event_size + header_size + payload_size;
    141   const size_t total_buffer_size =
    142       event_size + header_size + payload_buffer_size;
    143   void* data;
    144   Channel::MessagePtr message = NodeChannel::CreateEventMessage(
    145       total_buffer_size, total_size, &data, num_handles);
    146   auto* header = reinterpret_cast<MessageHeader*>(static_cast<uint8_t*>(data) +
    147                                                   event_size);
    148 
    149   // Populate the message header with information about serialized dispatchers.
    150   // The front of the message is always a MessageHeader followed by a
    151   // DispatcherHeader for each dispatcher to be sent.
    152   DispatcherHeader* new_dispatcher_headers;
    153   char* new_dispatcher_data;
    154   size_t total_num_dispatchers = num_new_dispatchers;
    155   std::vector<PlatformHandle> handles;
    156   if (original_message) {
    157     DCHECK(original_header);
    158     size_t original_dispatcher_headers_size =
    159         original_header->num_dispatchers * sizeof(DispatcherHeader);
    160     memcpy(header, original_header,
    161            original_dispatcher_headers_size + sizeof(MessageHeader));
    162     new_dispatcher_headers = reinterpret_cast<DispatcherHeader*>(
    163         reinterpret_cast<uint8_t*>(header + 1) +
    164         original_dispatcher_headers_size);
    165     total_num_dispatchers += original_header->num_dispatchers;
    166     size_t total_dispatcher_headers_size =
    167         total_num_dispatchers * sizeof(DispatcherHeader);
    168     char* original_dispatcher_data =
    169         reinterpret_cast<char*>(original_header + 1) +
    170         original_dispatcher_headers_size;
    171     char* dispatcher_data =
    172         reinterpret_cast<char*>(header + 1) + total_dispatcher_headers_size;
    173     size_t original_dispatcher_data_size = original_header_size -
    174                                            sizeof(MessageHeader) -
    175                                            original_dispatcher_headers_size;
    176     memcpy(dispatcher_data, original_dispatcher_data,
    177            original_dispatcher_data_size);
    178     new_dispatcher_data = dispatcher_data + original_dispatcher_data_size;
    179     auto handles_in_transit = original_message->TakeHandles();
    180     if (!handles_in_transit.empty()) {
    181       handles.resize(num_handles);
    182       for (size_t i = 0; i < handles_in_transit.size(); ++i)
    183         handles[i] = handles_in_transit[i].TakeHandle();
    184     }
    185     memcpy(reinterpret_cast<char*>(header) + header_size,
    186            reinterpret_cast<char*>(original_header) + original_header_size,
    187            original_payload_size);
    188   } else {
    189     new_dispatcher_headers = reinterpret_cast<DispatcherHeader*>(header + 1);
    190     // Serialized dispatcher state immediately follows the series of
    191     // DispatcherHeaders.
    192     new_dispatcher_data =
    193         reinterpret_cast<char*>(new_dispatcher_headers + num_new_dispatchers);
    194   }
    195 
    196   if (handles.empty() && num_new_handles)
    197     handles.resize(num_new_handles);
    198 
    199   header->num_dispatchers =
    200       base::CheckedNumeric<uint32_t>(total_num_dispatchers).ValueOrDie();
    201 
    202   // |header_size| is the total number of bytes preceding the message payload,
    203   // including all dispatcher headers and serialized dispatcher state.
    204   if (!base::IsValueInRangeForNumericType<uint32_t>(header_size))
    205     return MOJO_RESULT_OUT_OF_RANGE;
    206 
    207   header->header_size = static_cast<uint32_t>(header_size);
    208 
    209   if (num_new_dispatchers > 0) {
    210     size_t port_index = original_num_ports;
    211     size_t handle_index = original_num_handles;
    212     bool fail = false;
    213     for (size_t i = 0; i < num_new_dispatchers; ++i) {
    214       Dispatcher* d = new_dispatchers[i].dispatcher.get();
    215       DispatcherHeader* dh = &new_dispatcher_headers[i];
    216       const DispatcherInfo& info = new_dispatcher_info[i];
    217 
    218       // Fill in the header for this dispatcher.
    219       dh->type = static_cast<int32_t>(d->GetType());
    220       dh->num_bytes = info.num_bytes;
    221       dh->num_ports = info.num_ports;
    222       dh->num_platform_handles = info.num_handles;
    223 
    224       // Fill in serialized state, ports, and platform handles. We'll cancel
    225       // the send if the dispatcher implementation rejects for some reason.
    226       if (g_always_fail_handle_serialization ||
    227           !d->EndSerialize(
    228               static_cast<void*>(new_dispatcher_data),
    229               event->ports() + port_index,
    230               !handles.empty() ? handles.data() + handle_index : nullptr)) {
    231         fail = true;
    232         break;
    233       }
    234 
    235       new_dispatcher_data += info.num_bytes;
    236       port_index += info.num_ports;
    237       handle_index += info.num_handles;
    238     }
    239 
    240     if (fail) {
    241       // Release any platform handles we've accumulated. Their dispatchers
    242       // retain ownership when message creation fails, so these are not actually
    243       // leaking.
    244       for (auto& handle : handles)
    245         handle.release();
    246 
    247       // Leave the original message in place on failure if applicable.
    248       if (original_message)
    249         *out_message = std::move(original_message);
    250       return MOJO_RESULT_INVALID_ARGUMENT;
    251     }
    252 
    253     // Take ownership of all the handles and move them into message storage.
    254     message->SetHandles(std::move(handles));
    255   }
    256 
    257   *out_message = std::move(message);
    258   *out_header = header;
    259   *out_header_size = header_size;
    260   *out_user_payload = reinterpret_cast<uint8_t*>(header) + header_size;
    261   return MOJO_RESULT_OK;
    262 }
    263 
    264 base::subtle::Atomic32 g_message_count = 0;
    265 
    266 void IncrementMessageCount() {
    267   base::subtle::NoBarrier_AtomicIncrement(&g_message_count, 1);
    268 }
    269 
    270 void DecrementMessageCount() {
    271   base::subtle::NoBarrier_AtomicIncrement(&g_message_count, -1);
    272 }
    273 
    274 // class MessageMemoryDumpProvider : public base::trace_event::MemoryDumpProvider {
    275 //  public:
    276 //   MessageMemoryDumpProvider() {
    277 //     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
    278 //         this, "MojoMessages", nullptr);
    279 //   }
    280 
    281 //   ~MessageMemoryDumpProvider() override {
    282 //     base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
    283 //         this);
    284 //   }
    285 
    286 //  private:
    287 //   // base::trace_event::MemoryDumpProvider:
    288 //   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
    289 //                     base::trace_event::ProcessMemoryDump* pmd) override {
    290 //     auto* dump = pmd->CreateAllocatorDump("mojo/messages");
    291 //     dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
    292 //                     base::trace_event::MemoryAllocatorDump::kUnitsObjects,
    293 //                     base::subtle::NoBarrier_Load(&g_message_count));
    294 //     return true;
    295 //   }
    296 
    297 //   DISALLOW_COPY_AND_ASSIGN(MessageMemoryDumpProvider);
    298 // };
    299 
    300 // void EnsureMemoryDumpProviderExists() {
    301 //   static base::NoDestructor<MessageMemoryDumpProvider> provider;
    302 //   ALLOW_UNUSED_LOCAL(provider);
    303 // }
    304 
    305 }  // namespace
    306 
    307 // static
    308 const ports::UserMessage::TypeInfo UserMessageImpl::kUserMessageTypeInfo = {};
    309 
    310 UserMessageImpl::~UserMessageImpl() {
    311   if (HasContext() && context_destructor_) {
    312     DCHECK(!channel_message_);
    313     DCHECK(!has_serialized_handles_);
    314     context_destructor_(context_);
    315   } else if (IsSerialized() && has_serialized_handles_) {
    316     // Ensure that any handles still serialized within this message are
    317     // extracted and closed so they don't leak.
    318     std::vector<MojoHandle> handles(num_handles());
    319     MojoResult result =
    320         ExtractSerializedHandles(ExtractBadHandlePolicy::kSkip, handles.data());
    321     if (result == MOJO_RESULT_OK) {
    322       for (auto handle : handles) {
    323         if (handle != MOJO_HANDLE_INVALID)
    324           Core::Get()->Close(handle);
    325       }
    326     }
    327 
    328     if (!pending_handle_attachments_.empty()) {
    329       Core::Get()->ReleaseDispatchersForTransit(pending_handle_attachments_,
    330                                                 false);
    331       for (const auto& dispatcher : pending_handle_attachments_)
    332         Core::Get()->Close(dispatcher.local_handle);
    333     }
    334   }
    335 
    336   DecrementMessageCount();
    337 }
    338 
    339 // static
    340 std::unique_ptr<ports::UserMessageEvent>
    341 UserMessageImpl::CreateEventForNewMessage() {
    342   auto message_event = std::make_unique<ports::UserMessageEvent>(0);
    343   message_event->AttachMessage(
    344       base::WrapUnique(new UserMessageImpl(message_event.get())));
    345   return message_event;
    346 }
    347 
    348 // static
    349 MojoResult UserMessageImpl::CreateEventForNewSerializedMessage(
    350     uint32_t num_bytes,
    351     const Dispatcher::DispatcherInTransit* dispatchers,
    352     uint32_t num_dispatchers,
    353     std::unique_ptr<ports::UserMessageEvent>* out_event) {
    354   Channel::MessagePtr channel_message;
    355   void* header = nullptr;
    356   void* user_payload = nullptr;
    357   auto event = std::make_unique<ports::UserMessageEvent>(0);
    358   size_t header_size = 0;
    359   MojoResult rv = CreateOrExtendSerializedEventMessage(
    360       event.get(), num_bytes, num_bytes, dispatchers, num_dispatchers,
    361       &channel_message, &header, &header_size, &user_payload);
    362   if (rv != MOJO_RESULT_OK)
    363     return rv;
    364   event->AttachMessage(base::WrapUnique(
    365       new UserMessageImpl(event.get(), std::move(channel_message), header,
    366                           header_size, user_payload, num_bytes)));
    367   *out_event = std::move(event);
    368   return MOJO_RESULT_OK;
    369 }
    370 
    371 // static
    372 std::unique_ptr<UserMessageImpl> UserMessageImpl::CreateFromChannelMessage(
    373     ports::UserMessageEvent* message_event,
    374     Channel::MessagePtr channel_message,
    375     void* payload,
    376     size_t payload_size) {
    377   DCHECK(channel_message);
    378   if (payload_size < sizeof(MessageHeader))
    379     return nullptr;
    380 
    381   auto* header = static_cast<MessageHeader*>(payload);
    382   const size_t header_size = header->header_size;
    383   if (header_size > payload_size)
    384     return nullptr;
    385 
    386   void* user_payload = static_cast<uint8_t*>(payload) + header_size;
    387   const size_t user_payload_size = payload_size - header_size;
    388   return base::WrapUnique(
    389       new UserMessageImpl(message_event, std::move(channel_message), header,
    390                           header_size, user_payload, user_payload_size));
    391 }
    392 
    393 // static
    394 Channel::MessagePtr UserMessageImpl::FinalizeEventMessage(
    395     std::unique_ptr<ports::UserMessageEvent> message_event) {
    396   auto* message = message_event->GetMessage<UserMessageImpl>();
    397   DCHECK(message->IsSerialized());
    398 
    399   if (!message->is_committed_)
    400     return nullptr;
    401 
    402   Channel::MessagePtr channel_message = std::move(message->channel_message_);
    403   message->user_payload_ = nullptr;
    404   message->user_payload_size_ = 0;
    405 
    406   // Serialize the UserMessageEvent into the front of the message payload where
    407   // there is already space reserved for it.
    408   if (channel_message) {
    409     void* data;
    410     size_t size;
    411     NodeChannel::GetEventMessageData(channel_message.get(), &data, &size);
    412     message_event->Serialize(data);
    413   }
    414 
    415   return channel_message;
    416 }
    417 
    418 size_t UserMessageImpl::user_payload_capacity() const {
    419   DCHECK(IsSerialized());
    420   const size_t user_payload_offset =
    421       static_cast<uint8_t*>(user_payload_) -
    422       static_cast<const uint8_t*>(channel_message_->payload());
    423   const size_t message_capacity = channel_message_->capacity();
    424   DCHECK_LE(user_payload_offset, message_capacity);
    425   return message_capacity - user_payload_offset;
    426 }
    427 
    428 size_t UserMessageImpl::num_handles() const {
    429   DCHECK(IsSerialized());
    430   DCHECK(header_);
    431   return static_cast<const MessageHeader*>(header_)->num_dispatchers;
    432 }
    433 
    434 MojoResult UserMessageImpl::SetContext(
    435     uintptr_t context,
    436     MojoMessageContextSerializer serializer,
    437     MojoMessageContextDestructor destructor) {
    438   if (!context && (serializer || destructor))
    439     return MOJO_RESULT_INVALID_ARGUMENT;
    440   if (context && HasContext())
    441     return MOJO_RESULT_ALREADY_EXISTS;
    442   if (IsSerialized())
    443     return MOJO_RESULT_FAILED_PRECONDITION;
    444   context_ = context;
    445   context_serializer_ = serializer;
    446   context_destructor_ = destructor;
    447   return MOJO_RESULT_OK;
    448 }
    449 
    450 MojoResult UserMessageImpl::AppendData(uint32_t additional_payload_size,
    451                                        const MojoHandle* handles,
    452                                        uint32_t num_handles) {
    453   if (HasContext())
    454     return MOJO_RESULT_FAILED_PRECONDITION;
    455 
    456   std::vector<Dispatcher::DispatcherInTransit> dispatchers;
    457   if (num_handles > 0) {
    458     MojoResult acquire_result = Core::Get()->AcquireDispatchersForTransit(
    459         handles, num_handles, &dispatchers);
    460     if (acquire_result != MOJO_RESULT_OK)
    461       return acquire_result;
    462   }
    463 
    464   if (!IsSerialized()) {
    465     // First data for this message.
    466     Channel::MessagePtr channel_message;
    467     MojoResult rv = CreateOrExtendSerializedEventMessage(
    468         message_event_, additional_payload_size,
    469         std::max(additional_payload_size, kMinimumPayloadBufferSize),
    470         dispatchers.data(), num_handles, &channel_message, &header_,
    471         &header_size_, &user_payload_);
    472     if (num_handles > 0) {
    473       Core::Get()->ReleaseDispatchersForTransit(dispatchers,
    474                                                 rv == MOJO_RESULT_OK);
    475     }
    476     if (rv != MOJO_RESULT_OK)
    477       return MOJO_RESULT_ABORTED;
    478 
    479     user_payload_size_ = additional_payload_size;
    480     channel_message_ = std::move(channel_message);
    481     has_serialized_handles_ = true;
    482   } else {
    483     // Extend the existing message payload.
    484 
    485     // In order to avoid rather expensive message resizing on every handle
    486     // attachment operation, we merely lock and prepare the handle for transit
    487     // here, deferring serialization until |CommitSize()|.
    488     std::copy(dispatchers.begin(), dispatchers.end(),
    489               std::back_inserter(pending_handle_attachments_));
    490 
    491     if (additional_payload_size) {
    492       size_t header_offset =
    493           static_cast<uint8_t*>(header_) -
    494           static_cast<const uint8_t*>(channel_message_->payload());
    495       size_t user_payload_offset =
    496           static_cast<uint8_t*>(user_payload_) -
    497           static_cast<const uint8_t*>(channel_message_->payload());
    498       channel_message_->ExtendPayload(user_payload_offset + user_payload_size_ +
    499                                       additional_payload_size);
    500       header_ = static_cast<uint8_t*>(channel_message_->mutable_payload()) +
    501                 header_offset;
    502       user_payload_ =
    503           static_cast<uint8_t*>(channel_message_->mutable_payload()) +
    504           user_payload_offset;
    505       user_payload_size_ += additional_payload_size;
    506     }
    507   }
    508 
    509   return MOJO_RESULT_OK;
    510 }
    511 
    512 MojoResult UserMessageImpl::CommitSize() {
    513   if (!IsSerialized())
    514     return MOJO_RESULT_FAILED_PRECONDITION;
    515 
    516   if (is_committed_)
    517     return MOJO_RESULT_OK;
    518 
    519   if (!pending_handle_attachments_.empty()) {
    520     CreateOrExtendSerializedEventMessage(
    521         message_event_, user_payload_size_, user_payload_size_,
    522         pending_handle_attachments_.data(), pending_handle_attachments_.size(),
    523         &channel_message_, &header_, &header_size_, &user_payload_);
    524     Core::Get()->ReleaseDispatchersForTransit(pending_handle_attachments_,
    525                                               true);
    526     pending_handle_attachments_.clear();
    527   }
    528 
    529   is_committed_ = true;
    530   return MOJO_RESULT_OK;
    531 }
    532 
    533 MojoResult UserMessageImpl::SerializeIfNecessary() {
    534   if (IsSerialized())
    535     return MOJO_RESULT_FAILED_PRECONDITION;
    536 
    537   DCHECK(HasContext());
    538   DCHECK(!has_serialized_handles_);
    539   if (!context_serializer_)
    540     return MOJO_RESULT_NOT_FOUND;
    541 
    542   uintptr_t context = context_;
    543   context_ = 0;
    544   context_serializer_(reinterpret_cast<MojoMessageHandle>(message_event_),
    545                       context);
    546 
    547   if (context_destructor_)
    548     context_destructor_(context);
    549 
    550   has_serialized_handles_ = true;
    551   return MOJO_RESULT_OK;
    552 }
    553 
    554 MojoResult UserMessageImpl::ExtractSerializedHandles(
    555     ExtractBadHandlePolicy bad_handle_policy,
    556     MojoHandle* handles) {
    557   if (!IsSerialized())
    558     return MOJO_RESULT_FAILED_PRECONDITION;
    559 
    560   if (!has_serialized_handles_)
    561     return MOJO_RESULT_NOT_FOUND;
    562 
    563   const MessageHeader* header = static_cast<const MessageHeader*>(header_);
    564   const DispatcherHeader* dispatcher_headers =
    565       reinterpret_cast<const DispatcherHeader*>(header + 1);
    566 
    567   if (header->num_dispatchers > std::numeric_limits<uint16_t>::max())
    568     return MOJO_RESULT_ABORTED;
    569 
    570   if (header->num_dispatchers == 0)
    571     return MOJO_RESULT_OK;
    572 
    573   has_serialized_handles_ = false;
    574 
    575   std::vector<Dispatcher::DispatcherInTransit> dispatchers(
    576       header->num_dispatchers);
    577 
    578   size_t data_payload_index =
    579       sizeof(MessageHeader) +
    580       header->num_dispatchers * sizeof(DispatcherHeader);
    581   if (data_payload_index > header->header_size)
    582     return MOJO_RESULT_ABORTED;
    583   const char* dispatcher_data = reinterpret_cast<const char*>(
    584       dispatcher_headers + header->num_dispatchers);
    585   size_t port_index = 0;
    586   size_t platform_handle_index = 0;
    587   std::vector<PlatformHandleInTransit> handles_in_transit =
    588       channel_message_->TakeHandles();
    589   std::vector<PlatformHandle> msg_handles(handles_in_transit.size());
    590   for (size_t i = 0; i < handles_in_transit.size(); ++i) {
    591     DCHECK(!handles_in_transit[i].owning_process().is_valid());
    592     msg_handles[i] = handles_in_transit[i].TakeHandle();
    593   }
    594   for (size_t i = 0; i < header->num_dispatchers; ++i) {
    595     const DispatcherHeader& dh = dispatcher_headers[i];
    596     auto type = static_cast<Dispatcher::Type>(dh.type);
    597 
    598     base::CheckedNumeric<size_t> next_payload_index = data_payload_index;
    599     next_payload_index += dh.num_bytes;
    600     if (!next_payload_index.IsValid() ||
    601         header->header_size < next_payload_index.ValueOrDie()) {
    602       return MOJO_RESULT_ABORTED;
    603     }
    604 
    605     base::CheckedNumeric<size_t> next_port_index = port_index;
    606     next_port_index += dh.num_ports;
    607     if (!next_port_index.IsValid() ||
    608         message_event_->num_ports() < next_port_index.ValueOrDie()) {
    609       return MOJO_RESULT_ABORTED;
    610     }
    611 
    612     base::CheckedNumeric<size_t> next_platform_handle_index =
    613         platform_handle_index;
    614     next_platform_handle_index += dh.num_platform_handles;
    615     if (!next_platform_handle_index.IsValid() ||
    616         msg_handles.size() < next_platform_handle_index.ValueOrDie()) {
    617       return MOJO_RESULT_ABORTED;
    618     }
    619 
    620     PlatformHandle* out_handles =
    621         !msg_handles.empty() ? msg_handles.data() + platform_handle_index
    622                              : nullptr;
    623     dispatchers[i].dispatcher = Dispatcher::Deserialize(
    624         type, dispatcher_data, dh.num_bytes,
    625         message_event_->ports() + port_index, dh.num_ports, out_handles,
    626         dh.num_platform_handles);
    627     if (!dispatchers[i].dispatcher &&
    628         bad_handle_policy == ExtractBadHandlePolicy::kAbort) {
    629       return MOJO_RESULT_ABORTED;
    630     }
    631 
    632     dispatcher_data += dh.num_bytes;
    633     data_payload_index = next_payload_index.ValueOrDie();
    634     port_index = next_port_index.ValueOrDie();
    635     platform_handle_index = next_platform_handle_index.ValueOrDie();
    636   }
    637 
    638   if (!Core::Get()->AddDispatchersFromTransit(dispatchers, handles))
    639     return MOJO_RESULT_ABORTED;
    640 
    641   return MOJO_RESULT_OK;
    642 }
    643 
    644 // static
    645 void UserMessageImpl::FailHandleSerializationForTesting(bool fail) {
    646   g_always_fail_handle_serialization = fail;
    647 }
    648 
    649 UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event)
    650     : ports::UserMessage(&kUserMessageTypeInfo), message_event_(message_event) {
    651   // EnsureMemoryDumpProviderExists();
    652   IncrementMessageCount();
    653 }
    654 
    655 UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event,
    656                                  Channel::MessagePtr channel_message,
    657                                  void* header,
    658                                  size_t header_size,
    659                                  void* user_payload,
    660                                  size_t user_payload_size)
    661     : ports::UserMessage(&kUserMessageTypeInfo),
    662       message_event_(message_event),
    663       channel_message_(std::move(channel_message)),
    664       has_serialized_handles_(true),
    665       is_committed_(true),
    666       header_(header),
    667       header_size_(header_size),
    668       user_payload_(user_payload),
    669       user_payload_size_(user_payload_size) {
    670   // EnsureMemoryDumpProviderExists();
    671   IncrementMessageCount();
    672 }
    673 
    674 bool UserMessageImpl::WillBeRoutedExternally() {
    675   MojoResult result = SerializeIfNecessary();
    676   return result == MOJO_RESULT_OK || result == MOJO_RESULT_FAILED_PRECONDITION;
    677 }
    678 
    679 size_t UserMessageImpl::GetSizeIfSerialized() const {
    680   if (!IsSerialized())
    681     return 0;
    682   return user_payload_size_;
    683 }
    684 
    685 }  // namespace core
    686 }  // namespace mojo
    687