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 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef __IPC_GLUE_ENUMSERIALIZER_H__ 8 #define __IPC_GLUE_ENUMSERIALIZER_H__ 9 10 #include "CrashAnnotations.h" 11 #include "chrome/common/ipc_message_utils.h" 12 #include "mozilla/Assertions.h" 13 #include "mozilla/IntegerTypeTraits.h" 14 #include "nsExceptionHandler.h" 15 #include "nsLiteralString.h" 16 #include "nsString.h" 17 #include "nsTLiteralString.h" 18 19 class PickleIterator; 20 21 namespace IPC { 22 class Message; 23 class MessageReader; 24 class MessageWriter; 25 } // namespace IPC 26 27 #ifdef _MSC_VER 28 # pragma warning(disable : 4800) 29 #endif 30 31 namespace IPC { 32 33 /** 34 * Generic enum serializer. 35 * 36 * Consider using the specializations below, such as ContiguousEnumSerializer. 37 * 38 * This is a generic serializer for any enum type used in IPDL. 39 * Programmers can define ParamTraits<E> for enum type E by deriving 40 * EnumSerializer<E, MyEnumValidator> where MyEnumValidator is a struct 41 * that has to define a static IsLegalValue function returning whether 42 * a given value is a legal value of the enum type at hand. 43 * 44 * \sa https://developer.mozilla.org/en/IPDL/Type_Serialization 45 */ 46 template <typename E, typename EnumValidator> 47 struct EnumSerializer { 48 typedef E paramType; 49 50 // XXX(Bug 1690343) Should this be changed to 51 // std::make_unsigned_t<std::underlying_type_t<paramType>>, to make this more 52 // consistent with the type used for validating values? 53 typedef typename mozilla::UnsignedStdintTypeForSize<sizeof(paramType)>::Type 54 uintParamType; 55 WriteEnumSerializer56 static void Write(MessageWriter* aWriter, const paramType& aValue) { 57 // XXX This assertion is somewhat meaningless at least for E that don't have 58 // a fixed underlying type: if aValue weren't a legal value, we would 59 // already have UB where this function is called. 60 MOZ_RELEASE_ASSERT(EnumValidator::IsLegalValue( 61 static_cast<std::underlying_type_t<paramType>>(aValue))); 62 WriteParam(aWriter, uintParamType(aValue)); 63 } 64 ReadEnumSerializer65 static bool Read(MessageReader* aReader, paramType* aResult) { 66 uintParamType value; 67 if (!ReadParam(aReader, &value)) { 68 CrashReporter::AnnotateCrashReport( 69 CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"_ns); 70 return false; 71 } else if (!EnumValidator::IsLegalValue(value)) { 72 CrashReporter::AnnotateCrashReport( 73 CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"_ns); 74 return false; 75 } 76 *aResult = paramType(value); 77 return true; 78 } 79 }; 80 81 template <typename E, E MinLegal, E HighBound> 82 class ContiguousEnumValidator { 83 // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8: 84 // "comparison of unsigned expression >= 0 is always true" 85 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 86 template <typename T> IsLessThanOrEqual(T a,T b)87 static bool IsLessThanOrEqual(T a, T b) { 88 return a <= b; 89 } 90 91 public: 92 using IntegralType = std::underlying_type_t<E>; 93 static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal); 94 static constexpr auto kHighBoundIntegral = 95 static_cast<IntegralType>(HighBound); 96 IsLegalValue(const IntegralType e)97 static bool IsLegalValue(const IntegralType e) { 98 return IsLessThanOrEqual(kMinLegalIntegral, e) && e < kHighBoundIntegral; 99 } 100 }; 101 102 template <typename E, E MinLegal, E MaxLegal> 103 class ContiguousEnumValidatorInclusive { 104 // Silence overzealous -Wtype-limits bug in GCC fixed in GCC 4.8: 105 // "comparison of unsigned expression >= 0 is always true" 106 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 107 template <typename T> IsLessThanOrEqual(T a,T b)108 static bool IsLessThanOrEqual(T a, T b) { 109 return a <= b; 110 } 111 112 public: 113 using IntegralType = std::underlying_type_t<E>; 114 static constexpr auto kMinLegalIntegral = static_cast<IntegralType>(MinLegal); 115 static constexpr auto kMaxLegalIntegral = static_cast<IntegralType>(MaxLegal); 116 IsLegalValue(const IntegralType e)117 static bool IsLegalValue(const IntegralType e) { 118 return IsLessThanOrEqual(kMinLegalIntegral, e) && e <= kMaxLegalIntegral; 119 } 120 }; 121 122 template <typename E, E AllBits> 123 struct BitFlagsEnumValidator { IsLegalValueBitFlagsEnumValidator124 static bool IsLegalValue(const std::underlying_type_t<E> e) { 125 return (e & static_cast<std::underlying_type_t<E>>(AllBits)) == e; 126 } 127 }; 128 129 /** 130 * Specialization of EnumSerializer for enums with contiguous enum values. 131 * 132 * Provide two values: MinLegal, HighBound. An enum value x will be 133 * considered legal if MinLegal <= x < HighBound. 134 * 135 * For example, following is definition of serializer for enum type FOO. 136 * \code 137 * enum FOO { FOO_FIRST, FOO_SECOND, FOO_LAST, NUM_FOO }; 138 * 139 * template <> 140 * struct ParamTraits<FOO>: 141 * public ContiguousEnumSerializer<FOO, FOO_FIRST, NUM_FOO> {}; 142 * \endcode 143 * FOO_FIRST, FOO_SECOND, and FOO_LAST are valid value. 144 */ 145 template <typename E, E MinLegal, E HighBound> 146 struct ContiguousEnumSerializer 147 : EnumSerializer<E, ContiguousEnumValidator<E, MinLegal, HighBound>> {}; 148 149 /** 150 * This is similar to ContiguousEnumSerializer, but the last template 151 * parameter is expected to be the highest legal value, rather than a 152 * sentinel value. This is intended to support enumerations that don't 153 * have sentinel values. 154 */ 155 template <typename E, E MinLegal, E MaxLegal> 156 struct ContiguousEnumSerializerInclusive 157 : EnumSerializer<E, 158 ContiguousEnumValidatorInclusive<E, MinLegal, MaxLegal>> { 159 }; 160 161 /** 162 * Specialization of EnumSerializer for enums representing bit flags. 163 * 164 * Provide one value: AllBits. An enum value x will be 165 * considered legal if (x & AllBits) == x; 166 * 167 * Example: 168 * \code 169 * enum FOO { 170 * FOO_FIRST = 1 << 0, 171 * FOO_SECOND = 1 << 1, 172 * FOO_LAST = 1 << 2, 173 * ALL_BITS = (1 << 3) - 1 174 * }; 175 * 176 * template <> 177 * struct ParamTraits<FOO>: 178 * public BitFlagsEnumSerializer<FOO, FOO::ALL_BITS> {}; 179 * \endcode 180 */ 181 template <typename E, E AllBits> 182 struct BitFlagsEnumSerializer 183 : EnumSerializer<E, BitFlagsEnumValidator<E, AllBits>> {}; 184 185 } /* namespace IPC */ 186 187 #endif /* __IPC_GLUE_ENUMSERIALIZER_H__ */ 188