• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
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)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 
IncrementMessageCount()266 void IncrementMessageCount() {
267   base::subtle::NoBarrier_AtomicIncrement(&g_message_count, 1);
268 }
269 
DecrementMessageCount()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 
~UserMessageImpl()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>
CreateEventForNewMessage()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
CreateEventForNewSerializedMessage(uint32_t num_bytes,const Dispatcher::DispatcherInTransit * dispatchers,uint32_t num_dispatchers,std::unique_ptr<ports::UserMessageEvent> * out_event)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
CreateFromChannelMessage(ports::UserMessageEvent * message_event,Channel::MessagePtr channel_message,void * payload,size_t payload_size)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
FinalizeEventMessage(std::unique_ptr<ports::UserMessageEvent> message_event)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 
user_payload_capacity() const418 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 
num_handles() const428 size_t UserMessageImpl::num_handles() const {
429   DCHECK(IsSerialized());
430   DCHECK(header_);
431   return static_cast<const MessageHeader*>(header_)->num_dispatchers;
432 }
433 
SetContext(uintptr_t context,MojoMessageContextSerializer serializer,MojoMessageContextDestructor destructor)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 
AppendData(uint32_t additional_payload_size,const MojoHandle * handles,uint32_t num_handles)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 
CommitSize()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 
SerializeIfNecessary()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 
ExtractSerializedHandles(ExtractBadHandlePolicy bad_handle_policy,MojoHandle * handles)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
FailHandleSerializationForTesting(bool fail)645 void UserMessageImpl::FailHandleSerializationForTesting(bool fail) {
646   g_always_fail_handle_serialization = fail;
647 }
648 
UserMessageImpl(ports::UserMessageEvent * message_event)649 UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event)
650     : ports::UserMessage(&kUserMessageTypeInfo), message_event_(message_event) {
651   // EnsureMemoryDumpProviderExists();
652   IncrementMessageCount();
653 }
654 
UserMessageImpl(ports::UserMessageEvent * message_event,Channel::MessagePtr channel_message,void * header,size_t header_size,void * user_payload,size_t user_payload_size)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 
WillBeRoutedExternally()674 bool UserMessageImpl::WillBeRoutedExternally() {
675   MojoResult result = SerializeIfNecessary();
676   return result == MOJO_RESULT_OK || result == MOJO_RESULT_FAILED_PRECONDITION;
677 }
678 
GetSizeIfSerialized() const679 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