/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_COMMON_IPC_MESSAGE_UTILS_H_ #define CHROME_COMMON_IPC_MESSAGE_UTILS_H_ #include #include #include #include #include #include #include #include #include "ErrorList.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "base/pickle.h" #include "base/string_util.h" #include "chrome/common/ipc_message.h" #include "mozilla/CheckedInt.h" #include "mozilla/IntegerRange.h" #if defined(XP_WIN) # include #endif template class RefPtr; template class nsCOMPtr; namespace mozilla::ipc { class IProtocol; template struct IPDLParamTraits; class SharedMemory; // Implemented in ProtocolUtils.cpp MOZ_NEVER_INLINE void PickleFatalError(const char* aMsg, IProtocol* aActor); } // namespace mozilla::ipc namespace IPC { /** * Context used to serialize into an IPC::Message. Provides relevant context * used when serializing. */ class MOZ_STACK_CLASS MessageWriter final { public: explicit MessageWriter(Message& message, mozilla::ipc::IProtocol* actor = nullptr) : message_(message), actor_(actor) {} MessageWriter(const MessageWriter&) = delete; MessageWriter& operator=(const MessageWriter&) = delete; mozilla::ipc::IProtocol* GetActor() const { return actor_; } #define FORWARD_WRITE(name, type) \ bool Write##name(const type& result) { return message_.Write##name(result); } FORWARD_WRITE(Bool, bool) FORWARD_WRITE(Int16, int16_t) FORWARD_WRITE(UInt16, uint16_t) FORWARD_WRITE(Int, int) FORWARD_WRITE(Long, long) FORWARD_WRITE(ULong, unsigned long) FORWARD_WRITE(Int32, int32_t) FORWARD_WRITE(UInt32, uint32_t) FORWARD_WRITE(Int64, int64_t) FORWARD_WRITE(UInt64, uint64_t) FORWARD_WRITE(Double, double) FORWARD_WRITE(IntPtr, intptr_t) FORWARD_WRITE(UnsignedChar, unsigned char) FORWARD_WRITE(String, std::string) FORWARD_WRITE(WString, std::wstring) #undef FORWARD_WRITE bool WriteData(const char* data, uint32_t length) { return message_.WriteData(data, length); } bool WriteBytes(const void* data, uint32_t data_len) { return message_.WriteBytes(data, data_len); } bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity) { return message_.WriteBytesZeroCopy(data, data_len, capacity); } bool WriteSentinel(uint32_t sentinel) { return message_.WriteSentinel(sentinel); } bool WriteFileHandle(mozilla::UniqueFileHandle handle) { return message_.WriteFileHandle(std::move(handle)); } void WritePort(mozilla::ipc::ScopedPort port) { message_.WritePort(std::move(port)); } #if defined(XP_DARWIN) bool WriteMachSendRight(mozilla::UniqueMachSendRight port) { return message_.WriteMachSendRight(std::move(port)); } #endif void FatalError(const char* aErrorMsg) const { mozilla::ipc::PickleFatalError(aErrorMsg, actor_); } private: Message& message_; mozilla::ipc::IProtocol* actor_; }; /** * Context used to read data from an IPC::Message. Provides relevant context * used when deserializing and tracks iteration. */ class MOZ_STACK_CLASS MessageReader final { public: explicit MessageReader(const Message& message, mozilla::ipc::IProtocol* actor = nullptr) : message_(message), iter_(message), actor_(actor) {} MessageReader(const MessageReader&) = delete; MessageReader& operator=(const MessageReader&) = delete; mozilla::ipc::IProtocol* GetActor() const { return actor_; } #define FORWARD_READ(name, type) \ [[nodiscard]] bool Read##name(type* result) { \ return message_.Read##name(&iter_, result); \ } FORWARD_READ(Bool, bool) FORWARD_READ(Int16, int16_t) FORWARD_READ(UInt16, uint16_t) FORWARD_READ(Short, short) FORWARD_READ(Int, int) FORWARD_READ(Long, long) FORWARD_READ(ULong, unsigned long) FORWARD_READ(Int32, int32_t) FORWARD_READ(UInt32, uint32_t) FORWARD_READ(Int64, int64_t) FORWARD_READ(UInt64, uint64_t) FORWARD_READ(Double, double) FORWARD_READ(IntPtr, intptr_t) FORWARD_READ(UnsignedChar, unsigned char) FORWARD_READ(String, std::string) FORWARD_READ(WString, std::wstring) // Special version of ReadInt() which rejects negative values FORWARD_READ(Length, int); #undef FORWARD_READ [[nodiscard]] bool ReadBytesInto(void* data, uint32_t length) { return message_.ReadBytesInto(&iter_, data, length); } [[nodiscard]] bool IgnoreBytes(uint32_t length) { return message_.IgnoreBytes(&iter_, length); } [[nodiscard]] bool ReadSentinel(uint32_t sentinel) { return message_.ReadSentinel(&iter_, sentinel); } bool IgnoreSentinel() { return message_.IgnoreSentinel(&iter_); } bool HasBytesAvailable(uint32_t len) { return message_.HasBytesAvailable(&iter_, len); } void EndRead() { message_.EndRead(iter_, message_.type()); } [[nodiscard]] bool ConsumeFileHandle(mozilla::UniqueFileHandle* handle) { return message_.ConsumeFileHandle(&iter_, handle); } [[nodiscard]] bool ConsumePort(mozilla::ipc::ScopedPort* port) { return message_.ConsumePort(&iter_, port); } #if defined(XP_DARWIN) [[nodiscard]] bool ConsumeMachSendRight(mozilla::UniqueMachSendRight* port) { return message_.ConsumeMachSendRight(&iter_, port); } #endif void FatalError(const char* aErrorMsg) const { mozilla::ipc::PickleFatalError(aErrorMsg, actor_); } private: const Message& message_; PickleIterator iter_; mozilla::ipc::IProtocol* actor_; }; namespace detail { // Helper for checking `T::kHasDeprecatedReadParamPrivateConstructor` using a // fallback when the member isn't defined. template inline constexpr auto HasDeprecatedReadParamPrivateConstructor(int) -> decltype(T::kHasDeprecatedReadParamPrivateConstructor) { return T::kHasDeprecatedReadParamPrivateConstructor; } template inline constexpr bool HasDeprecatedReadParamPrivateConstructor(...) { return false; } } // namespace detail /** * Result type returned from some `ParamTraits::Read` implementations, and * from `IPC::ReadParam(MessageReader*)`. Either contains the value or * indicates a failure to deserialize. * * This type can be thought of as a variant on `Maybe`, except that it * unconditionally constructs the underlying value if it is default * constructible. This helps keep code size down, especially when calling * outparameter-based ReadParam implementations (bug 1815177). */ template || detail::HasDeprecatedReadParamPrivateConstructor(0)> class ReadResult { public: ReadResult() = default; template , int> = 0> MOZ_IMPLICIT ReadResult(U&& aData) : mIsOk(true), mData(std::forward(aData)) {} template explicit ReadResult(std::in_place_t, Args&&... aArgs) : mIsOk(true), mData(std::forward(aArgs)...) {} ReadResult(const ReadResult&) = default; ReadResult(ReadResult&&) = default; template , int> = 0> MOZ_IMPLICIT ReadResult& operator=(U&& aData) { mIsOk = true; mData = std::forward(aData); return *this; } ReadResult& operator=(const ReadResult&) = default; ReadResult& operator=(ReadResult&&) noexcept = default; // Check if the ReadResult contains a valid value. explicit operator bool() const { return isOk(); } bool isOk() const { return mIsOk; } // Get the data from this ReadResult. T& get() { MOZ_ASSERT(mIsOk); return mData; } const T& get() const { MOZ_ASSERT(mIsOk); return mData; } T& operator*() { return get(); } const T& operator*() const { return get(); } T* operator->() { return &get(); } const T* operator->() const { return &get(); } // Try to extract a `Maybe` from this ReadResult. mozilla::Maybe TakeMaybe() { if (mIsOk) { mIsOk = false; return mozilla::Some(std::move(mData)); } return mozilla::Nothing(); } // Get the underlying data from this ReadResult, even if not OK. // // This is only available for types which are default constructible, and is // used to optimize old-style `ReadParam` calls. T& GetStorage() { return mData; } // Compliment to `GetStorage` used to set the ReadResult into an OK state // without constructing the underlying value. void SetOk(bool aIsOk) { mIsOk = aIsOk; } private: bool mIsOk = false; T mData{}; }; template class ReadResult { public: ReadResult() = default; template , int> = 0> MOZ_IMPLICIT ReadResult(U&& aData) : mData(std::in_place, std::forward(aData)) {} template explicit ReadResult(std::in_place_t, Args&&... aArgs) : mData(std::in_place, std::forward(aArgs)...) {} ReadResult(const ReadResult&) = default; ReadResult(ReadResult&&) = default; template , int> = 0> MOZ_IMPLICIT ReadResult& operator=(U&& aData) { mData.reset(); mData.emplace(std::forward(aData)); return *this; } ReadResult& operator=(const ReadResult&) = default; ReadResult& operator=(ReadResult&&) noexcept = default; // Check if the ReadResult contains a valid value. explicit operator bool() const { return isOk(); } bool isOk() const { return mData.isSome(); } // Get the data from this ReadResult. T& get() { return mData.ref(); } const T& get() const { return mData.ref(); } T& operator*() { return get(); } const T& operator*() const { return get(); } T* operator->() { return &get(); } const T* operator->() const { return &get(); } // Try to extract a `Maybe` from this ReadResult. mozilla::Maybe TakeMaybe() { return std::move(mData); } // These methods are only available if the type is default constructible. T& GetStorage() = delete; void SetOk(bool aIsOk) = delete; private: mozilla::Maybe mData; }; //----------------------------------------------------------------------------- // An iterator class for reading the fields contained within a Message. class MessageIterator { public: explicit MessageIterator(const Message& m) : msg_(m), iter_(m) {} int NextInt() const { int val; if (!msg_.ReadInt(&iter_, &val)) NOTREACHED(); return val; } intptr_t NextIntPtr() const { intptr_t val; if (!msg_.ReadIntPtr(&iter_, &val)) NOTREACHED(); return val; } const std::string NextString() const { std::string val; if (!msg_.ReadString(&iter_, &val)) NOTREACHED(); return val; } const std::wstring NextWString() const { std::wstring val; if (!msg_.ReadWString(&iter_, &val)) NOTREACHED(); return val; } private: const Message& msg_; mutable PickleIterator iter_; }; //----------------------------------------------------------------------------- // ParamTraits specializations, etc. // // The full set of types ParamTraits is specialized upon contains *possibly* // repeated types: unsigned long may be uint32_t or size_t, unsigned long long // may be uint64_t or size_t, nsresult may be uint32_t, and so on. You can't // have ParamTraits *and* ParamTraits if unsigned int // is uint32_t -- that's multiple definitions, and you can only have one. // // You could use #ifs and macro conditions to avoid duplicates, but they'd be // hairy: heavily dependent upon OS and compiler author choices, forced to // address all conflicts by hand. Happily there's a better way. The basic // idea looks like this, where T -> U represents T inheriting from U: // // class ParamTraits

// | // --> class ParamTraits1

// | // --> class ParamTraits2

// | // --> class ParamTraitsN

// or however many levels // // The default specialization of ParamTraits{M}

is an empty class that // inherits from ParamTraits{M + 1}

(or nothing in the base case). // // Now partition the set of parameter types into sets without duplicates. // Assign each set of types to a level M. Then specialize ParamTraitsM for // each of those types. A reference to ParamTraits

will consist of some // number of empty classes inheriting in sequence, ending in a non-empty // ParamTraits{N}

. It's okay for the parameter types to be duplicative: // either name of a type will resolve to the same ParamTraits{N}

. // // The nice thing is that because templates are instantiated lazily, if we // indeed have uint32_t == unsigned int, say, with the former in level N and // the latter in M > N, ParamTraitsM won't be created (as long as // nobody uses ParamTraitsM, but why would you), and no duplicate // code will be compiled or extra symbols generated. It's as efficient at // runtime as manually figuring out and avoiding conflicts by #ifs. // // The scheme we follow below names the various classes according to the types // in them, and the number of ParamTraits levels is larger, but otherwise it's // exactly the above idea. // template struct ParamTraits; template inline void WriteParam(MessageWriter* writer, P&& p) { ParamTraits>::Write(writer, std::forward

(p)); } namespace detail { template inline constexpr auto ParamTraitsReadUsesOutParam() -> decltype(ParamTraits

::Read(std::declval(), std::declval())) { return true; } template inline constexpr auto ParamTraitsReadUsesOutParam() -> decltype(ParamTraits

::Read(std::declval()), bool{}) { return false; } } // namespace detail template inline bool WARN_UNUSED_RESULT ReadParam(MessageReader* reader, P* p) { if constexpr (!detail::ParamTraitsReadUsesOutParam

()) { auto maybe = ParamTraits

::Read(reader); if (maybe) { *p = std::move(*maybe); return true; } return false; } else { return ParamTraits

::Read(reader, p); } } template inline ReadResult

WARN_UNUSED_RESULT ReadParam(MessageReader* reader) { if constexpr (!detail::ParamTraitsReadUsesOutParam

()) { return ParamTraits

::Read(reader); } else { ReadResult

p; p.SetOk(ParamTraits

::Read(reader, &p.GetStorage())); return p; } } class MOZ_STACK_CLASS MessageBufferWriter { public: // Create a MessageBufferWriter to write `full_len` bytes into `writer`. // If the length exceeds a threshold, a shared memory region may be used // instead of including the data inline. // // NOTE: This does _NOT_ write out the length of the buffer. // NOTE: Data written this way _MUST_ be read using `MessageBufferReader`. MessageBufferWriter(MessageWriter* writer, uint32_t full_len); ~MessageBufferWriter(); MessageBufferWriter(const MessageBufferWriter&) = delete; MessageBufferWriter& operator=(const MessageBufferWriter&) = delete; // Write `len` bytes from `data` into the message. // // Exactly `full_len` bytes should be written across multiple calls before the // `MessageBufferWriter` is destroyed. // // WARNING: all writes (other than the last write) must be multiples of 4 // bytes in length. Not doing this will lead to padding being introduced into // the payload and break things. This can probably be improved in the future // with deeper integration between `MessageBufferWriter` and `Pickle`. bool WriteBytes(const void* data, uint32_t len); private: MessageWriter* writer_; RefPtr shmem_; char* buffer_ = nullptr; uint32_t remaining_ = 0; }; class MOZ_STACK_CLASS MessageBufferReader { public: // Create a MessageBufferReader to read `full_len` bytes from `reader` which // were written using `MessageBufferWriter`. // // NOTE: This may consume a shared memory region from the message, meaning // that the same data cannot be read multiple times. // NOTE: Data read this way _MUST_ be written using `MessageBufferWriter`. MessageBufferReader(MessageReader* reader, uint32_t full_len); ~MessageBufferReader(); MessageBufferReader(const MessageBufferReader&) = delete; MessageBufferReader& operator=(const MessageBufferReader&) = delete; // Read `count` bytes from the message into `data`. // // Exactly `full_len` bytes should be read across multiple calls before the // `MessageBufferReader` is destroyed. // // WARNING: all reads (other than the last read) must be multiples of 4 bytes // in length. Not doing this will lead to bytes being skipped in the payload // and break things. This can probably be improved in the future with deeper // integration between `MessageBufferReader` and `Pickle`. [[nodiscard]] bool ReadBytesInto(void* data, uint32_t len); private: MessageReader* reader_; RefPtr shmem_; const char* buffer_ = nullptr; uint32_t remaining_ = 0; }; // Whether or not it is safe to serialize the given type using // `WriteBytesOrShmem`. template constexpr bool kUseWriteBytes = !std::is_same_v>, bool> && (std::is_integral_v>> || std::is_floating_point_v>>); /** * Helper for writing a contiguous sequence (such as for a string or array) into * a message, with optimizations for basic integral and floating point types. * * Integral types will be copied into shared memory if the sequence exceeds 64k * bytes in size. * * Values written with this method must be read with `ReadSequenceParam`. * * The type parameter specifies the semantics to use, and should generally * either be `P&&` or `const P&`. The constness of the `data` argument should * match this parameter. */ template void WriteSequenceParam(MessageWriter* writer, std::remove_reference_t

* data, size_t length) { mozilla::CheckedUint32 ipc_length(length); if (!ipc_length.isValid()) { writer->FatalError("invalid length passed to WriteSequenceParam"); return; } writer->WriteUInt32(ipc_length.value()); if constexpr (kUseWriteBytes

) { mozilla::CheckedUint32 byte_length = ipc_length * sizeof(std::remove_reference_t

); if (!byte_length.isValid()) { writer->FatalError("invalid byte length in WriteSequenceParam"); return; } MessageBufferWriter buf_writer(writer, byte_length.value()); buf_writer.WriteBytes(data, byte_length.value()); } else { auto* end = data + length; for (auto* it = data; it != end; ++it) { WriteParam(writer, std::forward

(*it)); } } } template bool ReadSequenceParamImpl(MessageReader* reader, P* data, uint32_t length) { if (length == 0) { return true; } if (!data) { reader->FatalError("allocation failed in ReadSequenceParam"); return false; } if constexpr (kUseWriteBytes

) { mozilla::CheckedUint32 byte_length(length); byte_length *= sizeof(P); if (!byte_length.isValid()) { reader->FatalError("invalid byte length in ReadSequenceParam"); return false; } MessageBufferReader buf_reader(reader, byte_length.value()); return buf_reader.ReadBytesInto(data, byte_length.value()); } else { P* end = data + length; for (auto* it = data; it != end; ++it) { if (!ReadParam(reader, it)) { return false; } } return true; } } template bool ReadSequenceParamImpl(MessageReader* reader, mozilla::Maybe&& data, uint32_t length) { static_assert(!kUseWriteBytes

, "Cannot return an output iterator if !kUseWriteBytes

"); static_assert( std::is_base_of_v::iterator_category>, "must be Maybe"); if (length == 0) { return true; } if (!data) { reader->FatalError("allocation failed in ReadSequenceParam"); return false; } for (uint32_t i = 0; i < length; ++i) { auto elt = ReadParam

(reader); if (!elt) { return false; } *data.ref() = std::move(*elt); ++data.ref(); } return true; } /** * Helper for reading a contiguous sequence (such as a string or array) into a * message which was previously written using `WriteSequenceParam`. * * The function argument `allocator` will be called with the length of the * sequence, and must return either a pointer to the memory region which the * sequence should be read into, or a Maybe of a C++ output iterator which will * infallibly accept length elements, and append them to the output sequence. * * If the type satisfies kUseWriteBytes, output iterators are not supported. */ template bool WARN_UNUSED_RESULT ReadSequenceParam(MessageReader* reader, F&& allocator) { uint32_t length = 0; if (!reader->ReadUInt32(&length)) { reader->FatalError("failed to read byte length in ReadSequenceParam"); return false; } return ReadSequenceParamImpl

(reader, allocator(length), length); } // Temporary fallback class to allow types to declare serialization using the // IPDLParamTraits type class. Will be removed once all remaining // IPDLParamTraits implementations are gone. (bug 1754009) template struct ParamTraitsIPDLFallback { template static auto Write(MessageWriter* writer, R&& p) -> decltype(mozilla::ipc::IPDLParamTraits

::Write(writer, writer->GetActor(), std::forward(p))) { mozilla::ipc::IPDLParamTraits

::Write(writer, writer->GetActor(), std::forward(p)); } template static auto Read(MessageReader* reader, R* r) -> decltype(mozilla::ipc::IPDLParamTraits

::Read(reader, reader->GetActor(), r)) { return mozilla::ipc::IPDLParamTraits

::Read(reader, reader->GetActor(), r); } }; // Fundamental types. template struct ParamTraitsFundamental : ParamTraitsIPDLFallback

{}; template <> struct ParamTraitsFundamental { typedef bool param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteBool(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadBool(r); } }; template <> struct ParamTraitsFundamental { typedef int param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteInt(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadInt(r); } }; template <> struct ParamTraitsFundamental { typedef long param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteLong(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadLong(r); } }; template <> struct ParamTraitsFundamental { typedef unsigned long param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteULong(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadULong(r); } }; template <> struct ParamTraitsFundamental { typedef long long param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteBytes(&p, sizeof(param_type)); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadBytesInto(r, sizeof(*r)); } }; template <> struct ParamTraitsFundamental { typedef unsigned long long param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteBytes(&p, sizeof(param_type)); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadBytesInto(r, sizeof(*r)); } }; template <> struct ParamTraitsFundamental { typedef double param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteDouble(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadDouble(r); } }; // Fixed-size types. template struct ParamTraitsFixed : ParamTraitsFundamental

{}; template <> struct ParamTraitsFixed { typedef int16_t param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteInt16(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadInt16(r); } }; template <> struct ParamTraitsFixed { typedef uint16_t param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteUInt16(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadUInt16(r); } }; template <> struct ParamTraitsFixed { typedef uint32_t param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteUInt32(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadUInt32(r); } }; template <> struct ParamTraitsFixed { typedef int64_t param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteInt64(p); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadInt64(r); } }; template <> struct ParamTraitsFixed { typedef uint64_t param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteInt64(static_cast(p)); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadInt64(reinterpret_cast(r)); } }; // std::* types. template struct ParamTraitsStd : ParamTraitsFixed

{}; template struct ParamTraitsStd> { typedef std::basic_string param_type; static void Write(MessageWriter* writer, const param_type& p) { WriteSequenceParam(writer, p.data(), p.size()); } static bool Read(MessageReader* reader, param_type* r) { return ReadSequenceParam(reader, [&](uint32_t length) -> T* { r->resize(length); return r->data(); }); } }; template struct ParamTraitsStd> { typedef std::map param_type; static void Write(MessageWriter* writer, const param_type& p) { WriteParam(writer, static_cast(p.size())); typename param_type::const_iterator iter; for (iter = p.begin(); iter != p.end(); ++iter) { WriteParam(writer, iter->first); WriteParam(writer, iter->second); } } static bool Read(MessageReader* reader, param_type* r) { int size; if (!ReadParam(reader, &size) || size < 0) return false; for (int i = 0; i < size; ++i) { K k; if (!ReadParam(reader, &k)) return false; V& value = (*r)[k]; if (!ReadParam(reader, &value)) return false; } return true; } }; // Windows-specific types. template struct ParamTraitsWindows : ParamTraitsStd

{}; #if defined(XP_WIN) template <> struct ParamTraitsWindows { static_assert(sizeof(HANDLE) == sizeof(intptr_t), "Wrong size for HANDLE?"); static void Write(MessageWriter* writer, HANDLE p) { writer->WriteIntPtr(reinterpret_cast(p)); } static bool Read(MessageReader* reader, HANDLE* r) { return reader->ReadIntPtr(reinterpret_cast(r)); } }; template <> struct ParamTraitsWindows { static_assert(sizeof(HWND) == sizeof(intptr_t), "Wrong size for HWND?"); static void Write(MessageWriter* writer, HWND p) { writer->WriteIntPtr(reinterpret_cast(p)); } static bool Read(MessageReader* reader, HWND* r) { return reader->ReadIntPtr(reinterpret_cast(r)); } }; #endif // defined(XP_WIN) // Various ipc/chromium types. template struct ParamTraitsIPC : ParamTraitsWindows

{}; // `UniqueFileHandle` may be serialized over IPC channels. On the receiving // side, the UniqueFileHandle is a valid duplicate of the handle which was // transmitted. // // When sending a UniqueFileHandle, the handle must be valid at the time of // transmission. As transmission is asynchronous, this requires passing // ownership of the handle to IPC. // // A UniqueFileHandle may only be read once. After it has been read once, it // will be consumed, and future reads will return an invalid handle. template <> struct ParamTraitsIPC { typedef mozilla::UniqueFileHandle param_type; static void Write(MessageWriter* writer, param_type&& p) { const bool valid = p != nullptr; WriteParam(writer, valid); if (valid) { if (!writer->WriteFileHandle(std::move(p))) { writer->FatalError("Too many file handles for one message!"); NOTREACHED() << "Too many file handles for one message!"; } } } static bool Read(MessageReader* reader, param_type* r) { bool valid; if (!ReadParam(reader, &valid)) { reader->FatalError("Error reading file handle validity"); return false; } if (!valid) { *r = nullptr; return true; } if (!reader->ConsumeFileHandle(r)) { reader->FatalError("File handle not found in message!"); return false; } return true; } }; #if defined(XP_DARWIN) // `UniqueMachSendRight` may be serialized over IPC channels. On the receiving // side, the UniqueMachSendRight is the local name of the right which was // transmitted. // // When sending a UniqueMachSendRight, the right must be valid at the time of // transmission. As transmission is asynchronous, this requires passing // ownership of the handle to IPC. // // A UniqueMachSendRight may only be read once. After it has been read once, it // will be consumed, and future reads will return an invalid right. template <> struct ParamTraitsIPC { typedef mozilla::UniqueMachSendRight param_type; static void Write(MessageWriter* writer, param_type&& p) { const bool valid = p != nullptr; WriteParam(writer, valid); if (valid) { if (!writer->WriteMachSendRight(std::move(p))) { writer->FatalError("Too many mach send rights for one message!"); NOTREACHED() << "Too many mach send rights for one message!"; } } } static bool Read(MessageReader* reader, param_type* r) { bool valid; if (!ReadParam(reader, &valid)) { reader->FatalError("Error reading mach send right validity"); return false; } if (!valid) { *r = nullptr; return true; } if (!reader->ConsumeMachSendRight(r)) { reader->FatalError("Mach send right not found in message!"); return false; } return true; } }; #endif // Mozilla-specific types. template struct ParamTraitsMozilla : ParamTraitsIPC

{}; // Sending-only specialization for mozilla::Span. Uses an identical // serialization format as `const nsTArray&`. template struct ParamTraitsMozilla> { static void Write(MessageWriter* writer, mozilla::Span p) { WriteSequenceParam(writer, p.Elements(), p.Length()); } }; template <> struct ParamTraitsMozilla { typedef nsresult param_type; static void Write(MessageWriter* writer, const param_type& p) { writer->WriteUInt32(static_cast(p)); } static bool Read(MessageReader* reader, param_type* r) { return reader->ReadUInt32(reinterpret_cast(r)); } }; // See comments for the IPDLParamTraits specializations for RefPtr and // nsCOMPtr for more details. template struct ParamTraitsMozilla> { static void Write(MessageWriter* writer, const RefPtr& p) { ParamTraits::Write(writer, p.get()); } static bool Read(MessageReader* reader, RefPtr* r) { return ParamTraits::Read(reader, r); } }; template struct ParamTraitsMozilla> { static void Write(MessageWriter* writer, const nsCOMPtr& p) { ParamTraits::Write(writer, p.get()); } static bool Read(MessageReader* reader, nsCOMPtr* r) { RefPtr refptr; if (!ParamTraits::Read(reader, &refptr)) { return false; } *r = std::move(refptr); return true; } }; template struct ParamTraitsMozilla> { static void Write(MessageWriter* writer, const mozilla::NotNull& p) { ParamTraits::Write(writer, p.get()); } static ReadResult> Read(MessageReader* reader) { auto ptr = ReadParam(reader); if (!ptr) { return {}; } if (!*ptr) { reader->FatalError("unexpected null value"); return {}; } return mozilla::WrapNotNull(std::move(*ptr)); } }; // Finally, ParamTraits itself. template struct ParamTraits : ParamTraitsMozilla

{}; } // namespace IPC #endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_