diff options
Diffstat (limited to 'ipc/chromium/src/chrome/common/ipc_message_utils.h')
-rw-r--r-- | ipc/chromium/src/chrome/common/ipc_message_utils.h | 1093 |
1 files changed, 1093 insertions, 0 deletions
diff --git a/ipc/chromium/src/chrome/common/ipc_message_utils.h b/ipc/chromium/src/chrome/common/ipc_message_utils.h new file mode 100644 index 0000000000..90b94feaed --- /dev/null +++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h @@ -0,0 +1,1093 @@ +/* -*- 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 <cstdint> +#include <iterator> +#include <map> +#include <unordered_map> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> +#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 "build/build_config.h" +#include "chrome/common/ipc_message.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/IntegerRange.h" + +#if defined(OS_WIN) +# include <windows.h> +#endif + +template <typename T> +class RefPtr; +template <typename T> +class nsCOMPtr; + +namespace mozilla::ipc { +class IProtocol; +template <typename P> +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(OS_MACOSX) || defined(OS_IOS) + 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(OS_MACOSX) || defined(OS_IOS) + [[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 <typename T> +inline constexpr auto HasDeprecatedReadParamPrivateConstructor(int) + -> decltype(T::kHasDeprecatedReadParamPrivateConstructor) { + return T::kHasDeprecatedReadParamPrivateConstructor; +} + +template <typename T> +inline constexpr bool HasDeprecatedReadParamPrivateConstructor(...) { + return false; +} + +} // namespace detail + +/** + * Result type returned from some `ParamTraits<T>::Read` implementations, and + * from `IPC::ReadParam<T>(MessageReader*)`. Either contains the value or + * indicates a failure to deserialize. + * + * This type can be thought of as a variant on `Maybe<T>`, 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 <typename T, + bool = std::is_default_constructible_v<T> || + detail::HasDeprecatedReadParamPrivateConstructor<T>(0)> +class ReadResult { + public: + ReadResult() = default; + + template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> + MOZ_IMPLICIT ReadResult(U&& aData) + : mIsOk(true), mData(std::forward<U>(aData)) {} + + template <typename... Args> + explicit ReadResult(std::in_place_t, Args&&... aArgs) + : mIsOk(true), mData(std::forward<Args>(aArgs)...) {} + + ReadResult(const ReadResult&) = default; + ReadResult(ReadResult&&) = default; + + template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> + MOZ_IMPLICIT ReadResult& operator=(U&& aData) { + mIsOk = true; + mData = std::forward<U>(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<T>` from this ReadResult. + mozilla::Maybe<T> 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 <typename T> +class ReadResult<T, false> { + public: + ReadResult() = default; + + template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> + MOZ_IMPLICIT ReadResult(U&& aData) + : mData(std::in_place, std::forward<U>(aData)) {} + + template <typename... Args> + explicit ReadResult(std::in_place_t, Args&&... aArgs) + : mData(std::in_place, std::forward<Args>(aArgs)...) {} + + ReadResult(const ReadResult&) = default; + ReadResult(ReadResult&&) = default; + + template <typename U, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0> + MOZ_IMPLICIT ReadResult& operator=(U&& aData) { + mData.reset(); + mData.emplace(std::forward<U>(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<T>` from this ReadResult. + mozilla::Maybe<T> 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<T> 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<unsigned int> *and* ParamTraits<uint32_t> 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<P> +// | +// --> class ParamTraits1<P> +// | +// --> class ParamTraits2<P> +// | +// --> class ParamTraitsN<P> // or however many levels +// +// The default specialization of ParamTraits{M}<P> is an empty class that +// inherits from ParamTraits{M + 1}<P> (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<P> will consist of some +// number of empty classes inheriting in sequence, ending in a non-empty +// ParamTraits{N}<P>. It's okay for the parameter types to be duplicative: +// either name of a type will resolve to the same ParamTraits{N}<P>. +// +// 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<unsigned int> won't be created (as long as +// nobody uses ParamTraitsM<unsigned int>, 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 <class P> +struct ParamTraits; + +template <typename P> +inline void WriteParam(MessageWriter* writer, P&& p) { + ParamTraits<std::decay_t<P>>::Write(writer, std::forward<P>(p)); +} + +namespace detail { + +template <typename P> +inline constexpr auto ParamTraitsReadUsesOutParam() + -> decltype(ParamTraits<P>::Read(std::declval<MessageReader*>(), + std::declval<P*>())) { + return true; +} + +template <typename P> +inline constexpr auto ParamTraitsReadUsesOutParam() + -> decltype(ParamTraits<P>::Read(std::declval<MessageReader*>()), bool{}) { + return false; +} + +} // namespace detail + +template <typename P> +inline bool WARN_UNUSED_RESULT ReadParam(MessageReader* reader, P* p) { + if constexpr (!detail::ParamTraitsReadUsesOutParam<P>()) { + auto maybe = ParamTraits<P>::Read(reader); + if (maybe) { + *p = std::move(*maybe); + return true; + } + return false; + } else { + return ParamTraits<P>::Read(reader, p); + } +} + +template <typename P> +inline ReadResult<P> WARN_UNUSED_RESULT ReadParam(MessageReader* reader) { + if constexpr (!detail::ParamTraitsReadUsesOutParam<P>()) { + return ParamTraits<P>::Read(reader); + } else { + ReadResult<P> p; + p.SetOk(ParamTraits<P>::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<mozilla::ipc::SharedMemory> 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<mozilla::ipc::SharedMemory> shmem_; + const char* buffer_ = nullptr; + uint32_t remaining_ = 0; +}; + +// Whether or not it is safe to serialize the given type using +// `WriteBytesOrShmem`. +template <typename P> +constexpr bool kUseWriteBytes = + !std::is_same_v<std::remove_const_t<std::remove_reference_t<P>>, bool> && + (std::is_integral_v<std::remove_const_t<std::remove_reference_t<P>>> || + std::is_floating_point_v<std::remove_const_t<std::remove_reference_t<P>>>); + +/** + * 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 <typename P> +void WriteSequenceParam(MessageWriter* writer, std::remove_reference_t<P>* 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<P>) { + mozilla::CheckedUint32 byte_length = + ipc_length * sizeof(std::remove_reference_t<P>); + 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<P>(*it)); + } + } +} + +template <typename P> +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<P>) { + 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 <typename P, typename I> +bool ReadSequenceParamImpl(MessageReader* reader, mozilla::Maybe<I>&& data, + uint32_t length) { + static_assert(!kUseWriteBytes<P>, + "Cannot return an output iterator if !kUseWriteBytes<P>"); + static_assert( + std::is_base_of_v<std::output_iterator_tag, + typename std::iterator_traits<I>::iterator_category>, + "must be Maybe<output iterator>"); + 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<P>(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 <typename P, typename F> +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<P>(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 <class P> +struct ParamTraitsIPDLFallback { + template <class R> + static auto Write(MessageWriter* writer, R&& p) + -> decltype(mozilla::ipc::IPDLParamTraits<P>::Write(writer, + writer->GetActor(), + std::forward<R>(p))) { + mozilla::ipc::IPDLParamTraits<P>::Write(writer, writer->GetActor(), + std::forward<R>(p)); + } + template <class R> + static auto Read(MessageReader* reader, R* r) + -> decltype(mozilla::ipc::IPDLParamTraits<P>::Read(reader, + reader->GetActor(), + r)) { + return mozilla::ipc::IPDLParamTraits<P>::Read(reader, reader->GetActor(), + r); + } +}; + +// Fundamental types. + +template <class P> +struct ParamTraitsFundamental : ParamTraitsIPDLFallback<P> {}; + +template <> +struct ParamTraitsFundamental<bool> { + 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<int> { + 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<long> { + 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<unsigned long> { + 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<long long> { + 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<unsigned long long> { + 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<double> { + 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 <stdint.h> types. + +template <class P> +struct ParamTraitsFixed : ParamTraitsFundamental<P> {}; + +template <> +struct ParamTraitsFixed<int16_t> { + 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<uint16_t> { + 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<uint32_t> { + 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<int64_t> { + 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<uint64_t> { + typedef uint64_t param_type; + static void Write(MessageWriter* writer, const param_type& p) { + writer->WriteInt64(static_cast<int64_t>(p)); + } + static bool Read(MessageReader* reader, param_type* r) { + return reader->ReadInt64(reinterpret_cast<int64_t*>(r)); + } +}; + +// std::* types. + +template <class P> +struct ParamTraitsStd : ParamTraitsFixed<P> {}; + +template <class T> +struct ParamTraitsStd<std::basic_string<T>> { + typedef std::basic_string<T> param_type; + static void Write(MessageWriter* writer, const param_type& p) { + WriteSequenceParam<const T&>(writer, p.data(), p.size()); + } + static bool Read(MessageReader* reader, param_type* r) { + return ReadSequenceParam<T>(reader, [&](uint32_t length) -> T* { + r->resize(length); + return r->data(); + }); + } +}; + +template <class K, class V> +struct ParamTraitsStd<std::map<K, V>> { + typedef std::map<K, V> param_type; + static void Write(MessageWriter* writer, const param_type& p) { + WriteParam(writer, static_cast<int>(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 <class P> +struct ParamTraitsWindows : ParamTraitsStd<P> {}; + +#if defined(OS_WIN) +template <> +struct ParamTraitsWindows<HANDLE> { + static_assert(sizeof(HANDLE) == sizeof(intptr_t), "Wrong size for HANDLE?"); + + static void Write(MessageWriter* writer, HANDLE p) { + writer->WriteIntPtr(reinterpret_cast<intptr_t>(p)); + } + static bool Read(MessageReader* reader, HANDLE* r) { + return reader->ReadIntPtr(reinterpret_cast<intptr_t*>(r)); + } +}; + +template <> +struct ParamTraitsWindows<HWND> { + static_assert(sizeof(HWND) == sizeof(intptr_t), "Wrong size for HWND?"); + + static void Write(MessageWriter* writer, HWND p) { + writer->WriteIntPtr(reinterpret_cast<intptr_t>(p)); + } + static bool Read(MessageReader* reader, HWND* r) { + return reader->ReadIntPtr(reinterpret_cast<intptr_t*>(r)); + } +}; +#endif // defined(OS_WIN) + +// Various ipc/chromium types. + +template <class P> +struct ParamTraitsIPC : ParamTraitsWindows<P> {}; + +// `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<mozilla::UniqueFileHandle> { + 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(OS_MACOSX) || defined(OS_IOS) +// `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<mozilla::UniqueMachSendRight> { + 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 <class P> +struct ParamTraitsMozilla : ParamTraitsIPC<P> {}; + +// Sending-only specialization for mozilla::Span<T const>. Uses an identical +// serialization format as `const nsTArray<T>&`. +template <class T> +struct ParamTraitsMozilla<mozilla::Span<const T>> { + static void Write(MessageWriter* writer, mozilla::Span<const T> p) { + WriteSequenceParam<const T>(writer, p.Elements(), p.Length()); + } +}; + +template <> +struct ParamTraitsMozilla<nsresult> { + typedef nsresult param_type; + static void Write(MessageWriter* writer, const param_type& p) { + writer->WriteUInt32(static_cast<uint32_t>(p)); + } + static bool Read(MessageReader* reader, param_type* r) { + return reader->ReadUInt32(reinterpret_cast<uint32_t*>(r)); + } +}; + +// See comments for the IPDLParamTraits specializations for RefPtr<T> and +// nsCOMPtr<T> for more details. +template <class T> +struct ParamTraitsMozilla<RefPtr<T>> { + static void Write(MessageWriter* writer, const RefPtr<T>& p) { + ParamTraits<T*>::Write(writer, p.get()); + } + + static bool Read(MessageReader* reader, RefPtr<T>* r) { + return ParamTraits<T*>::Read(reader, r); + } +}; + +template <class T> +struct ParamTraitsMozilla<nsCOMPtr<T>> { + static void Write(MessageWriter* writer, const nsCOMPtr<T>& p) { + ParamTraits<T*>::Write(writer, p.get()); + } + + static bool Read(MessageReader* reader, nsCOMPtr<T>* r) { + RefPtr<T> refptr; + if (!ParamTraits<T*>::Read(reader, &refptr)) { + return false; + } + *r = std::move(refptr); + return true; + } +}; + +template <class T> +struct ParamTraitsMozilla<mozilla::NotNull<T>> { + static void Write(MessageWriter* writer, const mozilla::NotNull<T>& p) { + ParamTraits<T>::Write(writer, p.get()); + } + + static ReadResult<mozilla::NotNull<T>> Read(MessageReader* reader) { + auto ptr = ReadParam<T>(reader); + if (!ptr) { + return {}; + } + if (!*ptr) { + reader->FatalError("unexpected null value"); + return {}; + } + return mozilla::WrapNotNull(std::move(*ptr)); + } +}; + +// Finally, ParamTraits itself. + +template <class P> +struct ParamTraits : ParamTraitsMozilla<P> {}; + +} // namespace IPC + +#endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_ |