tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_