ipc_message_utils.h (37619B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #ifndef CHROME_COMMON_IPC_MESSAGE_UTILS_H_ 8 #define CHROME_COMMON_IPC_MESSAGE_UTILS_H_ 9 10 #include <cstdint> 11 #include <iterator> 12 #include <map> 13 #include <string> 14 #include <type_traits> 15 #include <utility> 16 #include <variant> 17 #include "ErrorList.h" 18 #include "base/logging.h" 19 #include "base/pickle.h" 20 #include "chrome/common/ipc_message.h" 21 #include "mozilla/CheckedInt.h" 22 #include "mozilla/ipc/SharedMemoryMapping.h" 23 24 #if defined(XP_WIN) 25 # include <windows.h> 26 #endif 27 28 template <typename T> 29 class RefPtr; 30 template <typename T> 31 class nsCOMPtr; 32 33 namespace mozilla::ipc { 34 class IProtocol; 35 namespace shared_memory { 36 class Cursor; 37 } 38 39 // Implemented in ProtocolUtils.cpp 40 MOZ_NEVER_INLINE void PickleFatalError(const char* aMsg, IProtocol* aActor); 41 } // namespace mozilla::ipc 42 43 namespace IPC { 44 45 /** 46 * This constant determines the threshold size (in bytes) for deciding whether 47 * shared memory should be used during serialization/deserialization handled 48 * by the MessageBufferWriter class. 49 * 50 * NOTE: Even above this threshold, if MessageBufferWriter fails to allocate a 51 * shared memory region, it may still fall-back to sending the message inline. 52 */ 53 constexpr uint32_t kMessageBufferShmemThreshold = 64 * 1024; // 64 KB 54 55 /** 56 * Context used to serialize into an IPC::Message. Provides relevant context 57 * used when serializing. 58 */ 59 class MOZ_STACK_CLASS MessageWriter final { 60 public: 61 explicit MessageWriter(Message& message, 62 mozilla::ipc::IProtocol* actor = nullptr) 63 : message_(message), actor_(actor) {} 64 65 MessageWriter(const MessageWriter&) = delete; 66 MessageWriter& operator=(const MessageWriter&) = delete; 67 68 mozilla::ipc::IProtocol* GetActor() const { return actor_; } 69 70 #define FORWARD_WRITE(name, type) \ 71 bool Write##name(const type& result) { return message_.Write##name(result); } 72 73 FORWARD_WRITE(Bool, bool) 74 FORWARD_WRITE(Int16, int16_t) 75 FORWARD_WRITE(UInt16, uint16_t) 76 FORWARD_WRITE(Int, int) 77 FORWARD_WRITE(Long, long) 78 FORWARD_WRITE(ULong, unsigned long) 79 FORWARD_WRITE(Int32, int32_t) 80 FORWARD_WRITE(UInt32, uint32_t) 81 FORWARD_WRITE(Int64, int64_t) 82 FORWARD_WRITE(UInt64, uint64_t) 83 FORWARD_WRITE(Double, double) 84 FORWARD_WRITE(IntPtr, intptr_t) 85 FORWARD_WRITE(UnsignedChar, unsigned char) 86 FORWARD_WRITE(String, std::string) 87 FORWARD_WRITE(WString, std::wstring) 88 89 #undef FORWARD_WRITE 90 91 template <class T> 92 bool WriteScalar(const T& result) { 93 return message_.WriteScalar(result); 94 } 95 96 bool WriteData(const char* data, uint32_t length) { 97 return message_.WriteData(data, length); 98 } 99 100 bool WriteBytes(const void* data, uint32_t data_len) { 101 return message_.WriteBytes(data, data_len); 102 } 103 104 bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity) { 105 return message_.WriteBytesZeroCopy(data, data_len, capacity); 106 } 107 108 bool WriteSentinel(uint32_t sentinel) { 109 return message_.WriteSentinel(sentinel); 110 } 111 112 bool WriteFileHandle(mozilla::UniqueFileHandle handle) { 113 return message_.WriteFileHandle(std::move(handle)); 114 } 115 116 void WritePort(mozilla::ipc::ScopedPort port) { 117 message_.WritePort(std::move(port)); 118 } 119 120 #if defined(XP_DARWIN) 121 bool WriteMachSendRight(mozilla::UniqueMachSendRight port) { 122 return message_.WriteMachSendRight(std::move(port)); 123 } 124 125 bool WriteMachReceiveRight(mozilla::UniqueMachReceiveRight port) { 126 return message_.WriteMachReceiveRight(std::move(port)); 127 } 128 #endif 129 130 void FatalError(const char* aErrorMsg) const { 131 mozilla::ipc::PickleFatalError(aErrorMsg, actor_); 132 } 133 134 void NoteLargeBufferShmemFailure(uint32_t aLargeBufferSize) { 135 message_.NoteLargeBufferShmemFailure(aLargeBufferSize); 136 } 137 138 private: 139 Message& message_; 140 mozilla::ipc::IProtocol* actor_; 141 }; 142 143 /** 144 * Context used to read data from an IPC::Message. Provides relevant context 145 * used when deserializing and tracks iteration. 146 */ 147 class MOZ_STACK_CLASS MessageReader final { 148 public: 149 explicit MessageReader(const Message& message, 150 mozilla::ipc::IProtocol* actor = nullptr) 151 : message_(message), iter_(message), actor_(actor) {} 152 153 MessageReader(const MessageReader&) = delete; 154 MessageReader& operator=(const MessageReader&) = delete; 155 156 mozilla::ipc::IProtocol* GetActor() const { return actor_; } 157 158 #define FORWARD_READ(name, type) \ 159 [[nodiscard]] bool Read##name(type* result) { \ 160 return message_.Read##name(&iter_, result); \ 161 } 162 163 FORWARD_READ(Bool, bool) 164 FORWARD_READ(Int16, int16_t) 165 FORWARD_READ(UInt16, uint16_t) 166 FORWARD_READ(Short, short) 167 FORWARD_READ(Int, int) 168 FORWARD_READ(Long, long) 169 FORWARD_READ(ULong, unsigned long) 170 FORWARD_READ(Int32, int32_t) 171 FORWARD_READ(UInt32, uint32_t) 172 FORWARD_READ(Int64, int64_t) 173 FORWARD_READ(UInt64, uint64_t) 174 FORWARD_READ(Double, double) 175 FORWARD_READ(IntPtr, intptr_t) 176 FORWARD_READ(UnsignedChar, unsigned char) 177 FORWARD_READ(String, std::string) 178 FORWARD_READ(WString, std::wstring) 179 180 // Special version of ReadInt() which rejects negative values 181 FORWARD_READ(Length, int); 182 183 #undef FORWARD_READ 184 185 template <class T> 186 [[nodiscard]] bool ReadScalar(T* const result) { 187 return message_.ReadScalar(&iter_, result); 188 } 189 190 [[nodiscard]] bool ReadBytesInto(void* data, uint32_t length) { 191 return message_.ReadBytesInto(&iter_, data, length); 192 } 193 194 [[nodiscard]] bool IgnoreBytes(uint32_t length) { 195 return message_.IgnoreBytes(&iter_, length); 196 } 197 198 [[nodiscard]] bool ReadSentinel(uint32_t sentinel) { 199 return message_.ReadSentinel(&iter_, sentinel); 200 } 201 202 bool IgnoreSentinel() { return message_.IgnoreSentinel(&iter_); } 203 204 bool HasBytesAvailable(uint32_t len) { 205 return message_.HasBytesAvailable(&iter_, len); 206 } 207 208 void EndRead() { message_.EndRead(iter_, message_.type()); } 209 210 [[nodiscard]] bool ConsumeFileHandle(mozilla::UniqueFileHandle* handle) { 211 return message_.ConsumeFileHandle(&iter_, handle); 212 } 213 214 [[nodiscard]] bool ConsumePort(mozilla::ipc::ScopedPort* port) { 215 return message_.ConsumePort(&iter_, port); 216 } 217 218 #if defined(XP_DARWIN) 219 [[nodiscard]] bool ConsumeMachSendRight(mozilla::UniqueMachSendRight* port) { 220 return message_.ConsumeMachSendRight(&iter_, port); 221 } 222 223 [[nodiscard]] bool ConsumeMachReceiveRight( 224 mozilla::UniqueMachReceiveRight* port) { 225 return message_.ConsumeMachReceiveRight(&iter_, port); 226 } 227 #endif 228 229 void FatalError(const char* aErrorMsg) const { 230 mozilla::ipc::PickleFatalError(aErrorMsg, actor_); 231 } 232 233 private: 234 const Message& message_; 235 PickleIterator iter_; 236 mozilla::ipc::IProtocol* actor_; 237 }; 238 239 namespace detail { 240 241 // Helper for checking `T::kHasDeprecatedReadParamPrivateConstructor` using a 242 // fallback when the member isn't defined. 243 template <typename T> 244 inline constexpr auto HasDeprecatedReadParamPrivateConstructor(int) 245 -> decltype(T::kHasDeprecatedReadParamPrivateConstructor) { 246 return T::kHasDeprecatedReadParamPrivateConstructor; 247 } 248 249 template <typename T> 250 inline constexpr bool HasDeprecatedReadParamPrivateConstructor(...) { 251 return false; 252 } 253 254 } // namespace detail 255 256 /** 257 * Result type returned from some `ParamTraits<T>::Read` implementations, and 258 * from `IPC::ReadParam<T>(MessageReader*)`. Either contains the value or 259 * indicates a failure to deserialize. 260 * 261 * This type can be thought of as a variant on `Maybe<T>`, except that it 262 * unconditionally constructs the underlying value if it is default 263 * constructible. This helps keep code size down, especially when calling 264 * outparameter-based ReadParam implementations (bug 1815177). 265 */ 266 template <typename T, 267 bool = std::is_default_constructible_v<T> || 268 detail::HasDeprecatedReadParamPrivateConstructor<T>(0)> 269 class ReadResult { 270 public: 271 ReadResult() = default; 272 273 template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> 274 MOZ_IMPLICIT ReadResult(U&& aData) 275 : mIsOk(true), mData(std::forward<U>(aData)) {} 276 277 template <typename... Args> 278 explicit ReadResult(std::in_place_t, Args&&... aArgs) 279 : mIsOk(true), mData(std::forward<Args>(aArgs)...) {} 280 281 ReadResult(const ReadResult&) = default; 282 ReadResult(ReadResult&&) = default; 283 284 template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> 285 MOZ_IMPLICIT ReadResult& operator=(U&& aData) { 286 mIsOk = true; 287 mData = std::forward<U>(aData); 288 return *this; 289 } 290 291 ReadResult& operator=(const ReadResult&) = default; 292 ReadResult& operator=(ReadResult&&) noexcept = default; 293 294 // Check if the ReadResult contains a valid value. 295 explicit operator bool() const { return isOk(); } 296 bool isOk() const { return mIsOk; } 297 298 // Get the data from this ReadResult. 299 T& get() { 300 MOZ_ASSERT(mIsOk); 301 return mData; 302 } 303 const T& get() const { 304 MOZ_ASSERT(mIsOk); 305 return mData; 306 } 307 308 T& operator*() { return get(); } 309 const T& operator*() const { return get(); } 310 311 T* operator->() { return &get(); } 312 const T* operator->() const { return &get(); } 313 314 // Try to extract a `Maybe<T>` from this ReadResult. 315 mozilla::Maybe<T> TakeMaybe() { 316 if (mIsOk) { 317 mIsOk = false; 318 return mozilla::Some(std::move(mData)); 319 } 320 return mozilla::Nothing(); 321 } 322 323 // Get the underlying data from this ReadResult, even if not OK. 324 // 325 // This is only available for types which are default constructible, and is 326 // used to optimize old-style `ReadParam` calls. 327 T& GetStorage() { return mData; } 328 329 // Compliment to `GetStorage` used to set the ReadResult into an OK state 330 // without constructing the underlying value. 331 void SetOk(bool aIsOk) { mIsOk = aIsOk; } 332 333 private: 334 bool mIsOk = false; 335 T mData{}; 336 }; 337 338 template <typename T> 339 class ReadResult<T, false> { 340 public: 341 ReadResult() = default; 342 343 template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> 344 MOZ_IMPLICIT ReadResult(U&& aData) 345 : mData(std::in_place, std::forward<U>(aData)) {} 346 347 template <typename... Args> 348 explicit ReadResult(std::in_place_t, Args&&... aArgs) 349 : mData(std::in_place, std::forward<Args>(aArgs)...) {} 350 351 ReadResult(const ReadResult&) = default; 352 ReadResult(ReadResult&&) = default; 353 354 template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> 355 MOZ_IMPLICIT ReadResult& operator=(U&& aData) { 356 mData.reset(); 357 mData.emplace(std::forward<U>(aData)); 358 return *this; 359 } 360 361 ReadResult& operator=(const ReadResult&) = default; 362 ReadResult& operator=(ReadResult&&) noexcept = default; 363 364 // Check if the ReadResult contains a valid value. 365 explicit operator bool() const { return isOk(); } 366 bool isOk() const { return mData.isSome(); } 367 368 // Get the data from this ReadResult. 369 T& get() { return mData.ref(); } 370 const T& get() const { return mData.ref(); } 371 372 T& operator*() { return get(); } 373 const T& operator*() const { return get(); } 374 375 T* operator->() { return &get(); } 376 const T* operator->() const { return &get(); } 377 378 // Try to extract a `Maybe<T>` from this ReadResult. 379 mozilla::Maybe<T> TakeMaybe() { return std::move(mData); } 380 381 // These methods are only available if the type is default constructible. 382 T& GetStorage() = delete; 383 void SetOk(bool aIsOk) = delete; 384 385 private: 386 mozilla::Maybe<T> mData; 387 }; 388 389 //----------------------------------------------------------------------------- 390 // An iterator class for reading the fields contained within a Message. 391 392 class MessageIterator { 393 public: 394 explicit MessageIterator(const Message& m) : msg_(m), iter_(m) {} 395 int NextInt() const { 396 int val; 397 if (!msg_.ReadInt(&iter_, &val)) NOTREACHED(); 398 return val; 399 } 400 intptr_t NextIntPtr() const { 401 intptr_t val; 402 if (!msg_.ReadIntPtr(&iter_, &val)) NOTREACHED(); 403 return val; 404 } 405 const std::string NextString() const { 406 std::string val; 407 if (!msg_.ReadString(&iter_, &val)) NOTREACHED(); 408 return val; 409 } 410 const std::wstring NextWString() const { 411 std::wstring val; 412 if (!msg_.ReadWString(&iter_, &val)) NOTREACHED(); 413 return val; 414 } 415 416 private: 417 const Message& msg_; 418 mutable PickleIterator iter_; 419 }; 420 421 //----------------------------------------------------------------------------- 422 // ParamTraits specializations, etc. 423 // 424 // The full set of types ParamTraits is specialized upon contains *possibly* 425 // repeated types: unsigned long may be uint32_t or size_t, unsigned long long 426 // may be uint64_t or size_t, nsresult may be uint32_t, and so on. You can't 427 // have ParamTraits<unsigned int> *and* ParamTraits<uint32_t> if unsigned int 428 // is uint32_t -- that's multiple definitions, and you can only have one. 429 // 430 // You could use #ifs and macro conditions to avoid duplicates, but they'd be 431 // hairy: heavily dependent upon OS and compiler author choices, forced to 432 // address all conflicts by hand. Happily there's a better way. The basic 433 // idea looks like this, where T -> U represents T inheriting from U: 434 // 435 // class ParamTraits<P> 436 // | 437 // --> class ParamTraits1<P> 438 // | 439 // --> class ParamTraits2<P> 440 // | 441 // --> class ParamTraitsN<P> // or however many levels 442 // 443 // The default specialization of ParamTraits{M}<P> is an empty class that 444 // inherits from ParamTraits{M + 1}<P> (or nothing in the base case). 445 // 446 // Now partition the set of parameter types into sets without duplicates. 447 // Assign each set of types to a level M. Then specialize ParamTraitsM for 448 // each of those types. A reference to ParamTraits<P> will consist of some 449 // number of empty classes inheriting in sequence, ending in a non-empty 450 // ParamTraits{N}<P>. It's okay for the parameter types to be duplicative: 451 // either name of a type will resolve to the same ParamTraits{N}<P>. 452 // 453 // The nice thing is that because templates are instantiated lazily, if we 454 // indeed have uint32_t == unsigned int, say, with the former in level N and 455 // the latter in M > N, ParamTraitsM<unsigned int> won't be created (as long as 456 // nobody uses ParamTraitsM<unsigned int>, but why would you), and no duplicate 457 // code will be compiled or extra symbols generated. It's as efficient at 458 // runtime as manually figuring out and avoiding conflicts by #ifs. 459 // 460 // The scheme we follow below names the various classes according to the types 461 // in them, and the number of ParamTraits levels is larger, but otherwise it's 462 // exactly the above idea. 463 // 464 465 template <class P> 466 struct ParamTraits; 467 468 template <typename P> 469 inline void WriteParam(MessageWriter* writer, P&& p) { 470 ParamTraits<std::decay_t<P>>::Write(writer, std::forward<P>(p)); 471 } 472 473 namespace detail { 474 475 template <typename P> 476 inline constexpr auto ParamTraitsReadUsesOutParam() 477 -> decltype(ParamTraits<P>::Read(std::declval<MessageReader*>(), 478 std::declval<P*>())) { 479 return true; 480 } 481 482 template <typename P> 483 inline constexpr auto ParamTraitsReadUsesOutParam() 484 -> decltype(ParamTraits<P>::Read(std::declval<MessageReader*>()), bool{}) { 485 return false; 486 } 487 488 } // namespace detail 489 490 template <typename P> 491 [[nodiscard]] inline bool ReadParam(MessageReader* reader, P* p) { 492 if constexpr (!detail::ParamTraitsReadUsesOutParam<P>()) { 493 auto maybe = ParamTraits<P>::Read(reader); 494 if (maybe) { 495 *p = std::move(*maybe); 496 return true; 497 } 498 return false; 499 } else { 500 return ParamTraits<P>::Read(reader, p); 501 } 502 } 503 504 template <typename P> 505 [[nodiscard]] inline ReadResult<P> ReadParam(MessageReader* reader) { 506 if constexpr (!detail::ParamTraitsReadUsesOutParam<P>()) { 507 return ParamTraits<P>::Read(reader); 508 } else { 509 ReadResult<P> p; 510 p.SetOk(ParamTraits<P>::Read(reader, &p.GetStorage())); 511 return p; 512 } 513 } 514 515 class MOZ_STACK_CLASS MessageBufferWriter { 516 public: 517 // Create a MessageBufferWriter to write `full_len` bytes into `writer`. 518 // If the length exceeds a threshold, a shared memory region may be used 519 // instead of including the data inline. 520 // 521 // NOTE: This does _NOT_ write out the length of the buffer. 522 // NOTE: Data written this way _MUST_ be read using `MessageBufferReader`. 523 MessageBufferWriter(MessageWriter* writer, uint32_t full_len); 524 ~MessageBufferWriter(); 525 526 MessageBufferWriter(const MessageBufferWriter&) = delete; 527 MessageBufferWriter& operator=(const MessageBufferWriter&) = delete; 528 529 // Write `len` bytes from `data` into the message. 530 // 531 // Exactly `full_len` bytes should be written across multiple calls before the 532 // `MessageBufferWriter` is destroyed. 533 // 534 // WARNING: all writes (other than the last write) must be multiples of 4 535 // bytes in length. Not doing this will lead to padding being introduced into 536 // the payload and break things. This can probably be improved in the future 537 // with deeper integration between `MessageBufferWriter` and `Pickle`. 538 bool WriteBytes(const void* data, uint32_t len); 539 540 private: 541 MessageWriter* writer_; 542 mozilla::UniquePtr<mozilla::ipc::shared_memory::Cursor> shmem_cursor_; 543 uint32_t remaining_ = 0; 544 }; 545 546 class MOZ_STACK_CLASS MessageBufferReader { 547 public: 548 // Create a MessageBufferReader to read `full_len` bytes from `reader` which 549 // were written using `MessageBufferWriter`. 550 // 551 // NOTE: This may consume a shared memory region from the message, meaning 552 // that the same data cannot be read multiple times. 553 // NOTE: Data read this way _MUST_ be written using `MessageBufferWriter`. 554 MessageBufferReader(MessageReader* reader, uint32_t full_len); 555 ~MessageBufferReader(); 556 557 MessageBufferReader(const MessageBufferReader&) = delete; 558 MessageBufferReader& operator=(const MessageBufferReader&) = delete; 559 560 // Read `count` bytes from the message into `data`. 561 // 562 // Exactly `full_len` bytes should be read across multiple calls before the 563 // `MessageBufferReader` is destroyed. 564 // 565 // WARNING: all reads (other than the last read) must be multiples of 4 bytes 566 // in length. Not doing this will lead to bytes being skipped in the payload 567 // and break things. This can probably be improved in the future with deeper 568 // integration between `MessageBufferReader` and `Pickle`. 569 [[nodiscard]] bool ReadBytesInto(void* data, uint32_t len); 570 571 private: 572 MessageReader* reader_; 573 mozilla::UniquePtr<mozilla::ipc::shared_memory::Cursor> shmem_cursor_; 574 uint32_t remaining_ = 0; 575 }; 576 577 // Whether or not it is safe to serialize the given type using 578 // `WriteBytesOrShmem`. 579 template <typename P> 580 constexpr bool kUseWriteBytes = 581 !std::is_same_v<std::remove_const_t<std::remove_reference_t<P>>, bool> && 582 (std::is_integral_v<std::remove_const_t<std::remove_reference_t<P>>> || 583 std::is_floating_point_v<std::remove_const_t<std::remove_reference_t<P>>>); 584 585 /** 586 * Helper for writing a contiguous sequence (such as for a string or array) into 587 * a message, with optimizations for basic integral and floating point types. 588 * 589 * Integral types will be copied into shared memory if the sequence exceeds 64k 590 * bytes in size. 591 * 592 * Values written with this method must be read with `ReadSequenceParam`. 593 * 594 * The type parameter specifies the semantics to use, and should generally 595 * either be `P&&` or `const P&`. The constness of the `data` argument should 596 * match this parameter. 597 */ 598 template <typename P> 599 void WriteSequenceParam(MessageWriter* writer, std::remove_reference_t<P>* data, 600 size_t length) { 601 mozilla::CheckedUint32 ipc_length(length); 602 if (!ipc_length.isValid()) { 603 writer->FatalError("invalid length passed to WriteSequenceParam"); 604 return; 605 } 606 writer->WriteUInt32(ipc_length.value()); 607 608 if constexpr (kUseWriteBytes<P>) { 609 mozilla::CheckedUint32 byte_length = 610 ipc_length * sizeof(std::remove_reference_t<P>); 611 if (!byte_length.isValid()) { 612 writer->FatalError("invalid byte length in WriteSequenceParam"); 613 return; 614 } 615 MessageBufferWriter buf_writer(writer, byte_length.value()); 616 buf_writer.WriteBytes(data, byte_length.value()); 617 } else { 618 auto* end = data + length; 619 for (auto* it = data; it != end; ++it) { 620 WriteParam(writer, std::forward<P>(*it)); 621 } 622 } 623 } 624 625 template <typename P> 626 bool ReadSequenceParamImpl(MessageReader* reader, P* data, uint32_t length) { 627 if (length == 0) { 628 return true; 629 } 630 if (!data) { 631 reader->FatalError("allocation failed in ReadSequenceParam"); 632 return false; 633 } 634 635 if constexpr (kUseWriteBytes<P>) { 636 mozilla::CheckedUint32 byte_length(length); 637 byte_length *= sizeof(P); 638 if (!byte_length.isValid()) { 639 reader->FatalError("invalid byte length in ReadSequenceParam"); 640 return false; 641 } 642 MessageBufferReader buf_reader(reader, byte_length.value()); 643 return buf_reader.ReadBytesInto(data, byte_length.value()); 644 } else { 645 P* end = data + length; 646 for (auto* it = data; it != end; ++it) { 647 if (!ReadParam(reader, it)) { 648 return false; 649 } 650 } 651 return true; 652 } 653 } 654 655 template <typename P, typename I> 656 bool ReadSequenceParamImpl(MessageReader* reader, mozilla::Maybe<I>&& data, 657 uint32_t length) { 658 static_assert(!kUseWriteBytes<P>, 659 "Cannot return an output iterator if !kUseWriteBytes<P>"); 660 static_assert( 661 std::is_base_of_v<std::output_iterator_tag, 662 typename std::iterator_traits<I>::iterator_category>, 663 "must be Maybe<output iterator>"); 664 if (length == 0) { 665 return true; 666 } 667 if (!data) { 668 reader->FatalError("allocation failed in ReadSequenceParam"); 669 return false; 670 } 671 672 for (uint32_t i = 0; i < length; ++i) { 673 auto elt = ReadParam<P>(reader); 674 if (!elt) { 675 return false; 676 } 677 *data.ref() = std::move(*elt); 678 ++data.ref(); 679 } 680 return true; 681 } 682 683 /** 684 * Helper for reading a contiguous sequence (such as a string or array) into a 685 * message which was previously written using `WriteSequenceParam`. 686 * 687 * The function argument `allocator` will be called with the length of the 688 * sequence, and must return either a pointer to the memory region which the 689 * sequence should be read into, or a Maybe of a C++ output iterator which will 690 * infallibly accept length elements, and append them to the output sequence. 691 * 692 * If the type satisfies kUseWriteBytes, output iterators are not supported. 693 */ 694 template <typename P, typename F> 695 [[nodiscard]] bool ReadSequenceParam(MessageReader* reader, F&& allocator) { 696 uint32_t length = 0; 697 if (!reader->ReadUInt32(&length)) { 698 reader->FatalError("failed to read byte length in ReadSequenceParam"); 699 return false; 700 } 701 702 return ReadSequenceParamImpl<P>(reader, allocator(length), length); 703 } 704 705 // Fundamental types. 706 707 template <class P> 708 struct ParamTraitsFundamental; 709 710 template <> 711 struct ParamTraitsFundamental<bool> { 712 typedef bool param_type; 713 static void Write(MessageWriter* writer, const param_type& p) { 714 writer->WriteBool(p); 715 } 716 static bool Read(MessageReader* reader, param_type* r) { 717 return reader->ReadBool(r); 718 } 719 }; 720 721 template <> 722 struct ParamTraitsFundamental<char> { 723 typedef char param_type; 724 static void Write(MessageWriter* writer, const param_type& p) { 725 writer->WriteScalar(p); 726 } 727 static bool Read(MessageReader* reader, param_type* r) { 728 return reader->ReadScalar(r); 729 } 730 }; 731 732 template <> 733 struct ParamTraitsFundamental<int> { 734 typedef int param_type; 735 static void Write(MessageWriter* writer, const param_type& p) { 736 writer->WriteInt(p); 737 } 738 static bool Read(MessageReader* reader, param_type* r) { 739 return reader->ReadInt(r); 740 } 741 }; 742 743 template <> 744 struct ParamTraitsFundamental<long> { 745 typedef long param_type; 746 static void Write(MessageWriter* writer, const param_type& p) { 747 writer->WriteLong(p); 748 } 749 static bool Read(MessageReader* reader, param_type* r) { 750 return reader->ReadLong(r); 751 } 752 }; 753 754 template <> 755 struct ParamTraitsFundamental<unsigned long> { 756 typedef unsigned long param_type; 757 static void Write(MessageWriter* writer, const param_type& p) { 758 writer->WriteULong(p); 759 } 760 static bool Read(MessageReader* reader, param_type* r) { 761 return reader->ReadULong(r); 762 } 763 }; 764 765 template <> 766 struct ParamTraitsFundamental<long long> { 767 typedef long long param_type; 768 static void Write(MessageWriter* writer, const param_type& p) { 769 writer->WriteBytes(&p, sizeof(param_type)); 770 } 771 static bool Read(MessageReader* reader, param_type* r) { 772 return reader->ReadBytesInto(r, sizeof(*r)); 773 } 774 }; 775 776 template <> 777 struct ParamTraitsFundamental<unsigned long long> { 778 typedef unsigned long long param_type; 779 static void Write(MessageWriter* writer, const param_type& p) { 780 writer->WriteBytes(&p, sizeof(param_type)); 781 } 782 static bool Read(MessageReader* reader, param_type* r) { 783 return reader->ReadBytesInto(r, sizeof(*r)); 784 } 785 }; 786 787 template <> 788 struct ParamTraitsFundamental<double> { 789 typedef double param_type; 790 static void Write(MessageWriter* writer, const param_type& p) { 791 writer->WriteDouble(p); 792 } 793 static bool Read(MessageReader* reader, param_type* r) { 794 return reader->ReadDouble(r); 795 } 796 }; 797 798 // Fixed-size <stdint.h> types. 799 800 template <class P> 801 struct ParamTraitsFixed : ParamTraitsFundamental<P> {}; 802 803 template <> 804 struct ParamTraitsFixed<int8_t> { 805 typedef int8_t param_type; 806 static void Write(MessageWriter* writer, const param_type& p) { 807 writer->WriteScalar(p); 808 } 809 static bool Read(MessageReader* reader, param_type* r) { 810 return reader->ReadScalar(r); 811 } 812 }; 813 814 template <> 815 struct ParamTraitsFixed<uint8_t> { 816 typedef uint8_t param_type; 817 static void Write(MessageWriter* writer, const param_type& p) { 818 writer->WriteScalar(p); 819 } 820 static bool Read(MessageReader* reader, param_type* r) { 821 return reader->ReadScalar(r); 822 } 823 }; 824 825 template <> 826 struct ParamTraitsFixed<int16_t> { 827 typedef int16_t param_type; 828 static void Write(MessageWriter* writer, const param_type& p) { 829 writer->WriteInt16(p); 830 } 831 static bool Read(MessageReader* reader, param_type* r) { 832 return reader->ReadInt16(r); 833 } 834 }; 835 836 template <> 837 struct ParamTraitsFixed<uint16_t> { 838 typedef uint16_t param_type; 839 static void Write(MessageWriter* writer, const param_type& p) { 840 writer->WriteUInt16(p); 841 } 842 static bool Read(MessageReader* reader, param_type* r) { 843 return reader->ReadUInt16(r); 844 } 845 }; 846 847 template <> 848 struct ParamTraitsFixed<uint32_t> { 849 typedef uint32_t param_type; 850 static void Write(MessageWriter* writer, const param_type& p) { 851 writer->WriteUInt32(p); 852 } 853 static bool Read(MessageReader* reader, param_type* r) { 854 return reader->ReadUInt32(r); 855 } 856 }; 857 858 template <> 859 struct ParamTraitsFixed<int64_t> { 860 typedef int64_t param_type; 861 static void Write(MessageWriter* writer, const param_type& p) { 862 writer->WriteInt64(p); 863 } 864 static bool Read(MessageReader* reader, param_type* r) { 865 return reader->ReadInt64(r); 866 } 867 }; 868 869 template <> 870 struct ParamTraitsFixed<uint64_t> { 871 typedef uint64_t param_type; 872 static void Write(MessageWriter* writer, const param_type& p) { 873 writer->WriteInt64(static_cast<int64_t>(p)); 874 } 875 static bool Read(MessageReader* reader, param_type* r) { 876 return reader->ReadInt64(reinterpret_cast<int64_t*>(r)); 877 } 878 }; 879 880 // std::* types. 881 882 template <class P> 883 struct ParamTraitsStd : ParamTraitsFixed<P> {}; 884 885 template <class T> 886 struct ParamTraitsStd<std::basic_string<T>> { 887 typedef std::basic_string<T> param_type; 888 static void Write(MessageWriter* writer, const param_type& p) { 889 WriteSequenceParam<const T&>(writer, p.data(), p.size()); 890 } 891 static bool Read(MessageReader* reader, param_type* r) { 892 return ReadSequenceParam<T>(reader, [&](uint32_t length) -> T* { 893 r->resize(length); 894 return r->data(); 895 }); 896 } 897 }; 898 899 template <class K, class V> 900 struct ParamTraitsStd<std::map<K, V>> { 901 typedef std::map<K, V> param_type; 902 static void Write(MessageWriter* writer, const param_type& p) { 903 WriteParam(writer, static_cast<int>(p.size())); 904 typename param_type::const_iterator iter; 905 for (iter = p.begin(); iter != p.end(); ++iter) { 906 WriteParam(writer, iter->first); 907 WriteParam(writer, iter->second); 908 } 909 } 910 static bool Read(MessageReader* reader, param_type* r) { 911 int size; 912 if (!ReadParam(reader, &size) || size < 0) return false; 913 for (int i = 0; i < size; ++i) { 914 K k; 915 if (!ReadParam(reader, &k)) return false; 916 V& value = (*r)[k]; 917 if (!ReadParam(reader, &value)) return false; 918 } 919 return true; 920 } 921 }; 922 923 template <> 924 struct ParamTraitsStd<std::monostate> { 925 using param_type = std::monostate; 926 static void Write(MessageWriter*, const param_type&) {} 927 static bool Read(MessageReader*, param_type*) { return true; } 928 }; 929 930 template <class... Ts> 931 struct ParamTraitsStd<std::variant<Ts...>> { 932 using param_type = std::variant<Ts...>; 933 934 template <class U> 935 static void Write(MessageWriter* writer, U&& p) { 936 WriteParam(writer, static_cast<uint64_t>(p.index())); 937 std::visit( 938 [&](auto&& param) { 939 WriteParam(writer, std::forward<decltype(param)>(param)); 940 }, 941 std::forward<U>(p)); 942 } 943 944 static ReadResult<param_type> Read(MessageReader* reader) { 945 uint64_t index; 946 if (!ReadParam(reader, &index)) { 947 return {}; 948 } 949 return ReadI<0>(reader, static_cast<size_t>(index)); 950 } 951 952 private: 953 template <size_t I> 954 static ReadResult<param_type> ReadI(MessageReader* reader, size_t index) { 955 if constexpr (I >= std::variant_size_v<param_type>) { 956 return {}; // No matching variant index 957 } else { 958 if (index == I) { 959 using alt_type = std::variant_alternative_t<I, param_type>; 960 ReadResult<alt_type> alt = ReadParam<alt_type>(reader); 961 if (!alt) { 962 return {}; 963 } 964 return ReadResult<param_type>{std::in_place, std::in_place_index<I>, 965 std::move(alt.get())}; 966 } 967 return ReadI<I + 1>(reader, index); 968 } 969 } 970 }; 971 972 // Windows-specific types. 973 974 template <class P> 975 struct ParamTraitsWindows : ParamTraitsStd<P> {}; 976 977 #if defined(XP_WIN) 978 template <> 979 struct ParamTraitsWindows<HANDLE> { 980 static_assert(sizeof(HANDLE) == sizeof(intptr_t), "Wrong size for HANDLE?"); 981 982 static void Write(MessageWriter* writer, HANDLE p) { 983 writer->WriteIntPtr(reinterpret_cast<intptr_t>(p)); 984 } 985 static bool Read(MessageReader* reader, HANDLE* r) { 986 return reader->ReadIntPtr(reinterpret_cast<intptr_t*>(r)); 987 } 988 }; 989 990 template <> 991 struct ParamTraitsWindows<HWND> { 992 static_assert(sizeof(HWND) == sizeof(intptr_t), "Wrong size for HWND?"); 993 994 static void Write(MessageWriter* writer, HWND p) { 995 writer->WriteIntPtr(reinterpret_cast<intptr_t>(p)); 996 } 997 static bool Read(MessageReader* reader, HWND* r) { 998 return reader->ReadIntPtr(reinterpret_cast<intptr_t*>(r)); 999 } 1000 }; 1001 #endif // defined(XP_WIN) 1002 1003 // Various ipc/chromium types. 1004 1005 template <class P> 1006 struct ParamTraitsIPC : ParamTraitsWindows<P> {}; 1007 1008 // `UniqueFileHandle` may be serialized over IPC channels. On the receiving 1009 // side, the UniqueFileHandle is a valid duplicate of the handle which was 1010 // transmitted. 1011 // 1012 // When sending a UniqueFileHandle, the handle must be valid at the time of 1013 // transmission. As transmission is asynchronous, this requires passing 1014 // ownership of the handle to IPC. 1015 // 1016 // A UniqueFileHandle may only be read once. After it has been read once, it 1017 // will be consumed, and future reads will return an invalid handle. 1018 template <> 1019 struct ParamTraitsIPC<mozilla::UniqueFileHandle> { 1020 typedef mozilla::UniqueFileHandle param_type; 1021 static void Write(MessageWriter* writer, param_type&& p) { 1022 const bool valid = p != nullptr; 1023 WriteParam(writer, valid); 1024 if (valid) { 1025 if (!writer->WriteFileHandle(std::move(p))) { 1026 writer->FatalError("Too many file handles for one message!"); 1027 NOTREACHED() << "Too many file handles for one message!"; 1028 } 1029 } 1030 } 1031 static bool Read(MessageReader* reader, param_type* r) { 1032 bool valid; 1033 if (!ReadParam(reader, &valid)) { 1034 reader->FatalError("Error reading file handle validity"); 1035 return false; 1036 } 1037 1038 if (!valid) { 1039 *r = nullptr; 1040 return true; 1041 } 1042 1043 if (!reader->ConsumeFileHandle(r)) { 1044 reader->FatalError("File handle not found in message!"); 1045 return false; 1046 } 1047 return true; 1048 } 1049 }; 1050 1051 #if defined(XP_DARWIN) 1052 // `UniqueMachSendRight` may be serialized over IPC channels. On the receiving 1053 // side, the UniqueMachSendRight is the local name of the right which was 1054 // transmitted. 1055 // 1056 // When sending a UniqueMachSendRight, the right must be valid at the time of 1057 // transmission. As transmission is asynchronous, this requires passing 1058 // ownership of the handle to IPC. 1059 // 1060 // A UniqueMachSendRight may only be read once. After it has been read once, it 1061 // will be consumed, and future reads will return an invalid right. 1062 template <> 1063 struct ParamTraitsIPC<mozilla::UniqueMachSendRight> { 1064 typedef mozilla::UniqueMachSendRight param_type; 1065 static void Write(MessageWriter* writer, param_type&& p) { 1066 const bool valid = p != nullptr; 1067 WriteParam(writer, valid); 1068 if (valid) { 1069 if (!writer->WriteMachSendRight(std::move(p))) { 1070 writer->FatalError("Too many mach send rights for one message!"); 1071 NOTREACHED() << "Too many mach send rights for one message!"; 1072 } 1073 } 1074 } 1075 static bool Read(MessageReader* reader, param_type* r) { 1076 bool valid; 1077 if (!ReadParam(reader, &valid)) { 1078 reader->FatalError("Error reading mach send right validity"); 1079 return false; 1080 } 1081 1082 if (!valid) { 1083 *r = nullptr; 1084 return true; 1085 } 1086 1087 if (!reader->ConsumeMachSendRight(r)) { 1088 reader->FatalError("Mach send right not found in message!"); 1089 return false; 1090 } 1091 return true; 1092 } 1093 }; 1094 1095 // `UniqueMachReceiveRight` may be serialized over IPC channels. On the 1096 // receiving side, the UniqueMachReceiveRight is the local name of the right 1097 // which was transmitted. 1098 // 1099 // When sending a UniqueMachReceiveRight, the right must be valid at the time of 1100 // transmission. As transmission is asynchronous, this requires passing 1101 // ownership of the handle to IPC. 1102 // 1103 // A UniqueMachReceiveRight may only be read once. After it has been read once, 1104 // it will be consumed, and future reads will return an invalid right. 1105 template <> 1106 struct ParamTraitsIPC<mozilla::UniqueMachReceiveRight> { 1107 typedef mozilla::UniqueMachReceiveRight param_type; 1108 static void Write(MessageWriter* writer, param_type&& p) { 1109 const bool valid = p != nullptr; 1110 WriteParam(writer, valid); 1111 if (valid) { 1112 if (!writer->WriteMachReceiveRight(std::move(p))) { 1113 writer->FatalError("Too many mach receive rights for one message!"); 1114 NOTREACHED() << "Too many mach receive rights for one message!"; 1115 } 1116 } 1117 } 1118 static bool Read(MessageReader* reader, param_type* r) { 1119 bool valid; 1120 if (!ReadParam(reader, &valid)) { 1121 reader->FatalError("Error reading mach receive right validity"); 1122 return false; 1123 } 1124 1125 if (!valid) { 1126 *r = nullptr; 1127 return true; 1128 } 1129 1130 if (!reader->ConsumeMachReceiveRight(r)) { 1131 reader->FatalError("Mach receive right not found in message!"); 1132 return false; 1133 } 1134 return true; 1135 } 1136 }; 1137 #endif 1138 1139 // Mozilla-specific types. 1140 1141 template <class P> 1142 struct ParamTraitsMozilla : ParamTraitsIPC<P> {}; 1143 1144 // Sending-only specialization for mozilla::Span<T const>. Uses an identical 1145 // serialization format as `const nsTArray<T>&`. 1146 template <class T> 1147 struct ParamTraitsMozilla<mozilla::Span<const T>> { 1148 static void Write(MessageWriter* writer, mozilla::Span<const T> p) { 1149 WriteSequenceParam<const T>(writer, p.Elements(), p.Length()); 1150 } 1151 }; 1152 1153 template <> 1154 struct ParamTraitsMozilla<nsresult> { 1155 typedef nsresult param_type; 1156 static void Write(MessageWriter* writer, const param_type& p) { 1157 writer->WriteUInt32(static_cast<uint32_t>(p)); 1158 } 1159 static bool Read(MessageReader* reader, param_type* r) { 1160 return reader->ReadUInt32(reinterpret_cast<uint32_t*>(r)); 1161 } 1162 }; 1163 1164 // When being passed `RefPtr<T>` or `nsCOMPtr<T>`, forward to a specialization 1165 // for the underlying target type. The parameter type will be passed as `T*`, 1166 // and result as `RefPtr<T>*`. 1167 // 1168 // This is done explicitly to ensure that the deleted `&&` overload for 1169 // `operator T*` is not selected in generic contexts, and to support 1170 // deserializing into `nsCOMPtr<T>`. 1171 template <class T> 1172 struct ParamTraitsMozilla<RefPtr<T>> { 1173 static void Write(MessageWriter* writer, const RefPtr<T>& p) { 1174 ParamTraits<T*>::Write(writer, p.get()); 1175 } 1176 1177 static bool Read(MessageReader* reader, RefPtr<T>* r) { 1178 return ParamTraits<T*>::Read(reader, r); 1179 } 1180 }; 1181 1182 template <class T> 1183 struct ParamTraitsMozilla<nsCOMPtr<T>> { 1184 static void Write(MessageWriter* writer, const nsCOMPtr<T>& p) { 1185 ParamTraits<T*>::Write(writer, p.get()); 1186 } 1187 1188 static bool Read(MessageReader* reader, nsCOMPtr<T>* r) { 1189 RefPtr<T> refptr; 1190 if (!ParamTraits<T*>::Read(reader, &refptr)) { 1191 return false; 1192 } 1193 *r = std::move(refptr); 1194 return true; 1195 } 1196 }; 1197 1198 template <class T> 1199 struct ParamTraitsMozilla<mozilla::NotNull<T>> { 1200 static void Write(MessageWriter* writer, const mozilla::NotNull<T>& p) { 1201 ParamTraits<T>::Write(writer, p.get()); 1202 } 1203 1204 static ReadResult<mozilla::NotNull<T>> Read(MessageReader* reader) { 1205 auto ptr = ReadParam<T>(reader); 1206 if (!ptr) { 1207 return {}; 1208 } 1209 if (!*ptr) { 1210 reader->FatalError("unexpected null value"); 1211 return {}; 1212 } 1213 return mozilla::WrapNotNull(std::move(*ptr)); 1214 } 1215 }; 1216 1217 // Finally, ParamTraits itself. 1218 1219 template <class P> 1220 struct ParamTraits : ParamTraitsMozilla<P> {}; 1221 1222 } // namespace IPC 1223 1224 #endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_