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