From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- ipc/glue/IPCMessageUtils.h | 830 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 830 insertions(+) create mode 100644 ipc/glue/IPCMessageUtils.h (limited to 'ipc/glue/IPCMessageUtils.h') diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h new file mode 100644 index 000000000..094aa978a --- /dev/null +++ b/ipc/glue/IPCMessageUtils.h @@ -0,0 +1,830 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __IPC_GLUE_IPCMESSAGEUTILS_H__ +#define __IPC_GLUE_IPCMESSAGEUTILS_H__ + +#include "base/process_util.h" +#include "chrome/common/ipc_message_utils.h" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/dom/ipc/StructuredCloneData.h" +#include "mozilla/Maybe.h" +#include "mozilla/net/WebSocketFrame.h" +#include "mozilla/TimeStamp.h" +#ifdef XP_WIN +#include "mozilla/TimeStamp_windows.h" +#endif +#include "mozilla/TypeTraits.h" +#include "mozilla/IntegerTypeTraits.h" + +#include + +#ifdef MOZ_CRASHREPORTER +#include "nsExceptionHandler.h" +#endif +#include "nsID.h" +#include "nsIWidget.h" +#include "nsMemory.h" +#include "nsString.h" +#include "nsTArray.h" +#include "js/StructuredClone.h" +#include "nsCSSPropertyID.h" + +#ifdef _MSC_VER +#pragma warning( disable : 4800 ) +#endif + +#if !defined(OS_POSIX) +// This condition must be kept in sync with the one in +// ipc_message_utils.h, but this dummy definition of +// base::FileDescriptor acts as a static assert that we only get one +// def or the other (or neither, in which case code using +// FileDescriptor fails to build) +namespace base { struct FileDescriptor { }; } +#endif + +namespace mozilla { + +// This is a cross-platform approximation to HANDLE, which we expect +// to be typedef'd to void* or thereabouts. +typedef uintptr_t WindowsHandle; + +// XXX there are out of place and might be generally useful. Could +// move to nscore.h or something. +struct void_t { + bool operator==(const void_t&) const { return true; } +}; +struct null_t { + bool operator==(const null_t&) const { return true; } +}; + +struct SerializedStructuredCloneBuffer final +{ + SerializedStructuredCloneBuffer& + operator=(const SerializedStructuredCloneBuffer& aOther) + { + data.Clear(); + auto iter = aOther.data.Iter(); + while (!iter.Done()) { + data.WriteBytes(iter.Data(), iter.RemainingInSegment()); + iter.Advance(aOther.data, iter.RemainingInSegment()); + } + return *this; + } + + bool + operator==(const SerializedStructuredCloneBuffer& aOther) const + { + // The copy assignment operator and the equality operator are + // needed by the IPDL generated code. We relied on the copy + // assignment operator at some places but we never use the + // equality operator. + return false; + } + + JSStructuredCloneData data; +}; + +} // namespace mozilla + +namespace IPC { + +/** + * Maximum size, in bytes, of a single IPC message. + */ +static const uint32_t MAX_MESSAGE_SIZE = 65536; + +/** + * Generic enum serializer. + * + * Consider using the specializations below, such as ContiguousEnumSerializer. + * + * This is a generic serializer for any enum type used in IPDL. + * Programmers can define ParamTraits for enum type E by deriving + * EnumSerializer where MyEnumValidator is a struct + * that has to define a static IsLegalValue function returning whether + * a given value is a legal value of the enum type at hand. + * + * \sa https://developer.mozilla.org/en/IPDL/Type_Serialization + */ +template +struct EnumSerializer { + typedef E paramType; + typedef typename mozilla::UnsignedStdintTypeForSize::Type + uintParamType; + + static void Write(Message* aMsg, const paramType& aValue) { + MOZ_ASSERT(EnumValidator::IsLegalValue(aValue)); + WriteParam(aMsg, uintParamType(aValue)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { + uintParamType value; + if (!ReadParam(aMsg, aIter, &value)) { +#ifdef MOZ_CRASHREPORTER + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), + NS_LITERAL_CSTRING("Bad iter")); +#endif + return false; + } else if (!EnumValidator::IsLegalValue(paramType(value))) { +#ifdef MOZ_CRASHREPORTER + CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), + NS_LITERAL_CSTRING("Illegal value")); +#endif + return false; + } + *aResult = paramType(value); + return true; + } +}; + +template +class ContiguousEnumValidator +{ + // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8: + // "comparison of unsigned expression >= 0 is always true" + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 + template + static bool IsLessThanOrEqual(T a, T b) { return a <= b; } + +public: + static bool IsLegalValue(E e) + { + return IsLessThanOrEqual(MinLegal, e) && e < HighBound; + } +}; + +template +struct BitFlagsEnumValidator +{ + static bool IsLegalValue(E e) + { + return (e & AllBits) == e; + } +}; + +/** + * Specialization of EnumSerializer for enums with contiguous enum values. + * + * Provide two values: MinLegal, HighBound. An enum value x will be + * considered legal if MinLegal <= x < HighBound. + * + * For example, following is definition of serializer for enum type FOO. + * \code + * enum FOO { FOO_FIRST, FOO_SECOND, FOO_LAST, NUM_FOO }; + * + * template <> + * struct ParamTraits: + * public ContiguousEnumSerializer {}; + * \endcode + * FOO_FIRST, FOO_SECOND, and FOO_LAST are valid value. + */ +template +struct ContiguousEnumSerializer + : EnumSerializer> +{}; + +/** + * Specialization of EnumSerializer for enums representing bit flags. + * + * Provide one value: AllBits. An enum value x will be + * considered legal if (x & AllBits) == x; + * + * Example: + * \code + * enum FOO { + * FOO_FIRST = 1 << 0, + * FOO_SECOND = 1 << 1, + * FOO_LAST = 1 << 2, + * ALL_BITS = (1 << 3) - 1 + * }; + * + * template <> + * struct ParamTraits: + * public BitFlagsEnumSerializer {}; + * \endcode + */ +template +struct BitFlagsEnumSerializer + : EnumSerializer> +{}; + +template <> +struct ParamTraits + : public ContiguousEnumSerializer +{ }; + +template<> +struct ParamTraits +{ + typedef int8_t paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + aMsg->WriteBytes(&aParam, sizeof(aParam)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult)); + } +}; + +template<> +struct ParamTraits +{ + typedef uint8_t paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + aMsg->WriteBytes(&aParam, sizeof(aParam)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult)); + } +}; + +#if !defined(OS_POSIX) +// See above re: keeping definitions in sync +template<> +struct ParamTraits +{ + typedef base::FileDescriptor paramType; + static void Write(Message* aMsg, const paramType& aParam) { + NS_RUNTIMEABORT("FileDescriptor isn't meaningful on this platform"); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { + NS_RUNTIMEABORT("FileDescriptor isn't meaningful on this platform"); + return false; + } +}; +#endif // !defined(OS_POSIX) + +template <> +struct ParamTraits +{ + typedef nsACString paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + bool isVoid = aParam.IsVoid(); + aMsg->WriteBool(isVoid); + + if (isVoid) + // represents a nullptr pointer + return; + + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + aMsg->WriteBytes(aParam.BeginReading(), length); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + bool isVoid; + if (!aMsg->ReadBool(aIter, &isVoid)) + return false; + + if (isVoid) { + aResult->SetIsVoid(true); + return true; + } + + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + aResult->SetLength(length); + + return aMsg->ReadBytesInto(aIter, aResult->BeginWriting(), length); + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + if (aParam.IsVoid()) + aLog->append(L"(NULL)"); + else + aLog->append(UTF8ToWide(aParam.BeginReading())); + } +}; + +template <> +struct ParamTraits +{ + typedef nsAString paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + bool isVoid = aParam.IsVoid(); + aMsg->WriteBool(isVoid); + + if (isVoid) + // represents a nullptr pointer + return; + + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + aMsg->WriteBytes(aParam.BeginReading(), length * sizeof(char16_t)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + bool isVoid; + if (!aMsg->ReadBool(aIter, &isVoid)) + return false; + + if (isVoid) { + aResult->SetIsVoid(true); + return true; + } + + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + aResult->SetLength(length); + + return aMsg->ReadBytesInto(aIter, aResult->BeginWriting(), length * sizeof(char16_t)); + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + if (aParam.IsVoid()) + aLog->append(L"(NULL)"); + else { +#ifdef WCHAR_T_IS_UTF16 + aLog->append(reinterpret_cast(aParam.BeginReading())); +#else + uint32_t length = aParam.Length(); + for (uint32_t index = 0; index < length; index++) { + aLog->push_back(std::wstring::value_type(aParam[index])); + } +#endif + } + } +}; + +template <> +struct ParamTraits : ParamTraits +{ + typedef nsCString paramType; +}; + +template <> +struct ParamTraits : ParamTraits +{ + typedef nsLiteralCString paramType; +}; + +#ifdef MOZILLA_INTERNAL_API + +template<> +struct ParamTraits : ParamTraits +{ + typedef nsAutoCString paramType; +}; + +#endif // MOZILLA_INTERNAL_API + +template <> +struct ParamTraits : ParamTraits +{ + typedef nsString paramType; +}; + +template <> +struct ParamTraits : ParamTraits +{ + typedef nsLiteralString paramType; +}; + +// Pickle::ReadBytes and ::WriteBytes take the length in ints, so we must +// ensure there is no overflow. This returns |false| if it would overflow. +// Otherwise, it returns |true| and places the byte length in |aByteLength|. +bool ByteLengthIsValid(uint32_t aNumElements, size_t aElementSize, int* aByteLength); + +// Note: IPDL will sometimes codegen specialized implementations of +// nsTArray serialization and deserialization code in +// implementSpecialArrayPickling(). This is needed when ParamTraits +// is not defined. +template +struct ParamTraits> +{ + typedef nsTArray paramType; + + // We write arrays of integer or floating-point data using a single pickling + // call, rather than writing each element individually. We deliberately do + // not use mozilla::IsPod here because it is perfectly reasonable to have + // a data structure T for which IsPod::value is true, yet also have a + // ParamTraits specialization. + static const bool sUseWriteBytes = (mozilla::IsIntegral::value || + mozilla::IsFloatingPoint::value); + + static void Write(Message* aMsg, const paramType& aParam) + { + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + + if (sUseWriteBytes) { + int pickledLength = 0; + MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength)); + aMsg->WriteBytes(aParam.Elements(), pickledLength); + } else { + const E* elems = aParam.Elements(); + for (uint32_t index = 0; index < length; index++) { + WriteParam(aMsg, elems[index]); + } + } + } + + // This method uses infallible allocation so that an OOM failure will + // show up as an OOM crash rather than an IPC FatalError. + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + + if (sUseWriteBytes) { + int pickledLength = 0; + if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) { + return false; + } + + E* elements = aResult->AppendElements(length); + return aMsg->ReadBytesInto(aIter, elements, pickledLength); + } else { + aResult->SetCapacity(length); + + for (uint32_t index = 0; index < length; index++) { + E* element = aResult->AppendElement(); + if (!ReadParam(aMsg, aIter, element)) { + return false; + } + } + return true; + } + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + for (uint32_t index = 0; index < aParam.Length(); index++) { + if (index) { + aLog->append(L" "); + } + LogParam(aParam[index], aLog); + } + } +}; + +template +struct ParamTraits> +{ + typedef FallibleTArray paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, static_cast&>(aParam)); + } + + // Deserialize the array infallibly, but return a FallibleTArray. + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + nsTArray temp; + if (!ReadParam(aMsg, aIter, &temp)) + return false; + + aResult->SwapElements(temp); + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + LogParam(static_cast&>(aParam), aLog); + } +}; + +template +struct ParamTraits> : ParamTraits> +{ + typedef AutoTArray paramType; +}; + +template<> +struct ParamTraits +{ + typedef float paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + aMsg->WriteBytes(&aParam, sizeof(paramType)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult)); + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + aLog->append(StringPrintf(L"%g", aParam)); + } +}; + +template <> +struct ParamTraits + : public ContiguousEnumSerializer +{}; + +template<> +struct ParamTraits +{ + typedef mozilla::void_t paramType; + static void Write(Message* aMsg, const paramType& aParam) { } + static bool + Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + *aResult = paramType(); + return true; + } +}; + +template<> +struct ParamTraits +{ + typedef mozilla::null_t paramType; + static void Write(Message* aMsg, const paramType& aParam) { } + static bool + Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + *aResult = paramType(); + return true; + } +}; + +template<> +struct ParamTraits +{ + typedef nsID paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.m0); + WriteParam(aMsg, aParam.m1); + WriteParam(aMsg, aParam.m2); + for (unsigned int i = 0; i < mozilla::ArrayLength(aParam.m3); i++) { + WriteParam(aMsg, aParam.m3[i]); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + if(!ReadParam(aMsg, aIter, &(aResult->m0)) || + !ReadParam(aMsg, aIter, &(aResult->m1)) || + !ReadParam(aMsg, aIter, &(aResult->m2))) + return false; + + for (unsigned int i = 0; i < mozilla::ArrayLength(aResult->m3); i++) + if (!ReadParam(aMsg, aIter, &(aResult->m3[i]))) + return false; + + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + aLog->append(L"{"); + aLog->append(StringPrintf(L"%8.8X-%4.4X-%4.4X-", + aParam.m0, + aParam.m1, + aParam.m2)); + for (unsigned int i = 0; i < mozilla::ArrayLength(aParam.m3); i++) + aLog->append(StringPrintf(L"%2.2X", aParam.m3[i])); + aLog->append(L"}"); + } +}; + +template<> +struct ParamTraits +{ + typedef mozilla::TimeDuration paramType; + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mValue); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, &aResult->mValue); + }; +}; + +template<> +struct ParamTraits +{ + typedef mozilla::TimeStamp paramType; + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mValue); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, &aResult->mValue); + }; +}; + +#ifdef XP_WIN + +template<> +struct ParamTraits +{ + typedef mozilla::TimeStampValue paramType; + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.mGTC); + WriteParam(aMsg, aParam.mQPC); + WriteParam(aMsg, aParam.mHasQPC); + WriteParam(aMsg, aParam.mIsNull); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return (ReadParam(aMsg, aIter, &aResult->mGTC) && + ReadParam(aMsg, aIter, &aResult->mQPC) && + ReadParam(aMsg, aIter, &aResult->mHasQPC) && + ReadParam(aMsg, aIter, &aResult->mIsNull)); + } +}; + +#endif + +template <> +struct ParamTraits +{ + typedef mozilla::dom::ipc::StructuredCloneData paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + aParam.WriteIPCParams(aMsg); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return aResult->ReadIPCParams(aMsg, aIter); + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + LogParam(aParam.DataLength(), aLog); + } +}; + +template <> +struct ParamTraits +{ + typedef mozilla::net::WebSocketFrameData paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + aParam.WriteIPCParams(aMsg); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return aResult->ReadIPCParams(aMsg, aIter); + } +}; + +template <> +struct ParamTraits +{ + typedef JSStructuredCloneData paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + MOZ_ASSERT(!(aParam.Size() % sizeof(uint64_t))); + WriteParam(aMsg, aParam.Size()); + auto iter = aParam.Iter(); + while (!iter.Done()) { + aMsg->WriteBytes(iter.Data(), iter.RemainingInSegment(), sizeof(uint64_t)); + iter.Advance(aParam, iter.RemainingInSegment()); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + size_t length = 0; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + MOZ_ASSERT(!(length % sizeof(uint64_t))); + + mozilla::BufferList buffers(0, 0, 4096); + + // Borrowing is not suitable to use for IPC to hand out data + // because we often want to store the data somewhere for + // processing after IPC has released the underlying buffers. One + // case is PContentChild::SendGetXPCOMProcessAttributes. We can't + // return a borrowed buffer because the out param outlives the + // IPDL callback. + if (length && !aMsg->ExtractBuffers(aIter, length, &buffers, sizeof(uint64_t))) { + return false; + } + + bool success; + mozilla::BufferList out = + buffers.MoveFallible(&success); + if (!success) { + return false; + } + + *aResult = JSStructuredCloneData(Move(out)); + + return true; + } +}; + +template <> +struct ParamTraits +{ + typedef mozilla::SerializedStructuredCloneBuffer paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.data); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, &aResult->data); + } + + static void Log(const paramType& aParam, std::wstring* aLog) + { + LogParam(aParam.data.Size(), aLog); + } +}; + +template <> +struct ParamTraits + : public BitFlagsEnumSerializer +{ +}; + +template +struct ParamTraits> +{ + typedef mozilla::Maybe paramType; + + static void Write(Message* msg, const paramType& param) + { + if (param.isSome()) { + WriteParam(msg, true); + WriteParam(msg, param.value()); + } else { + WriteParam(msg, false); + } + } + + static bool Read(const Message* msg, PickleIterator* iter, paramType* result) + { + bool isSome; + if (!ReadParam(msg, iter, &isSome)) { + return false; + } + if (isSome) { + T tmp; + if (!ReadParam(msg, iter, &tmp)) { + return false; + } + *result = mozilla::Some(mozilla::Move(tmp)); + } else { + *result = mozilla::Nothing(); + } + return true; + } +}; + +} /* namespace IPC */ + +#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */ -- cgit v1.2.3