webkit  2cdf99a9e3038c7e01b3c37e8ad903ecbe5eecf1
https://github.com/WebKit/webkit
safe_math.h
Go to the documentation of this file.
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_NUMERICS_SAFE_MATH_H_
6 #define BASE_NUMERICS_SAFE_MATH_H_
7 
8 #include <stddef.h>
9 
10 #include <limits>
11 #include <type_traits>
12 
13 #include "base/logging.h"
15 
16 namespace base
17 {
18 
19 namespace internal
20 {
21 
22 // CheckedNumeric implements all the logic and operators for detecting integer
23 // boundary conditions such as overflow, underflow, and invalid conversions.
24 // The CheckedNumeric type implicitly converts from floating point and integer
25 // data types, and contains overloads for basic arithmetic operations (i.e.: +,
26 // -, *, /, %).
27 //
28 // The following methods convert from CheckedNumeric to standard numeric values:
29 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has
30 // has not wrapped and is not the result of an invalid conversion).
31 // ValueOrDie() - Returns the underlying value. If the state is not valid this
32 // call will crash on a CHECK.
33 // ValueOrDefault() - Returns the current value, or the supplied default if the
34 // state is not valid.
35 // ValueFloating() - Returns the underlying floating point value (valid only
36 // only for floating point CheckedNumeric types).
37 //
38 // Bitwise operations are explicitly not supported, because correct
39 // handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
40 // operations are explicitly not supported because they could result in a crash
41 // on a CHECK condition. You should use patterns like the following for these
42 // operations:
43 // Bitwise operation:
44 // CheckedNumeric<int> checked_int = untrusted_input_value;
45 // int x = checked_int.ValueOrDefault(0) | kFlagValues;
46 // Comparison:
47 // CheckedNumeric<size_t> checked_size = untrusted_input_value;
48 // checked_size += HEADER LENGTH;
49 // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
50 // Do stuff...
51 template <typename T>
53 {
54  static_assert(std::is_arithmetic<T>::value, "CheckedNumeric<T>: T must be a numeric type.");
55 
56  public:
57  typedef T type;
58 
60 
61  // Copy constructor.
62  template <typename Src>
63  CheckedNumeric(const CheckedNumeric<Src> &rhs) : state_(rhs.ValueUnsafe(), rhs.validity())
64  {
65  }
66 
67  template <typename Src>
68  CheckedNumeric(Src value, RangeConstraint validity) : state_(value, validity)
69  {
70  }
71 
72  // This is not an explicit constructor because we implicitly upgrade regular
73  // numerics to CheckedNumerics to make them easier to use.
74  template <typename Src>
75  CheckedNumeric(Src value) // NOLINT(runtime/explicit)
76  : state_(value)
77  {
78  static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric.");
79  }
80 
81  // This is not an explicit constructor because we want a seamless conversion
82  // from StrictNumeric types.
83  template <typename Src>
84  CheckedNumeric(StrictNumeric<Src> value) // NOLINT(runtime/explicit)
85  : state_(static_cast<Src>(value))
86  {
87  }
88 
89  // IsValid() is the public API to test if a CheckedNumeric is currently valid.
90  bool IsValid() const { return validity() == RANGE_VALID; }
91 
92  // ValueOrDie() The primary accessor for the underlying value. If the current
93  // state is not valid it will CHECK and crash.
94  T ValueOrDie() const
95  {
96  CHECK(IsValid());
97  return state_.value();
98  }
99 
100  // ValueOrDefault(T default_value) A convenience method that returns the
101  // current value if the state is valid, and the supplied default_value for
102  // any other state.
103  T ValueOrDefault(T default_value) const { return IsValid() ? state_.value() : default_value; }
104 
105  // ValueFloating() - Since floating point values include their validity state,
106  // we provide an easy method for extracting them directly, without a risk of
107  // crashing on a CHECK.
108  T ValueFloating() const
109  {
110  static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
111  return CheckedNumeric<T>::cast(*this).ValueUnsafe();
112  }
113 
114  // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
115  // tests and to avoid a big matrix of friend operator overloads. But the
116  // values it returns are likely to change in the future.
117  // Returns: current validity state (i.e. valid, overflow, underflow, nan).
118  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
119  // saturation/wrapping so we can expose this state consistently and implement
120  // saturated arithmetic.
121  RangeConstraint validity() const { return state_.validity(); }
122 
123  // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
124  // for tests and to avoid a big matrix of friend operator overloads. But the
125  // values it returns are likely to change in the future.
126  // Returns: the raw numeric value, regardless of the current state.
127  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
128  // saturation/wrapping so we can expose this state consistently and implement
129  // saturated arithmetic.
130  T ValueUnsafe() const { return state_.value(); }
131 
132  // Prototypes for the supported arithmetic operator overloads.
133  template <typename Src>
134  CheckedNumeric &operator+=(Src rhs);
135  template <typename Src>
136  CheckedNumeric &operator-=(Src rhs);
137  template <typename Src>
138  CheckedNumeric &operator*=(Src rhs);
139  template <typename Src>
140  CheckedNumeric &operator/=(Src rhs);
141  template <typename Src>
142  CheckedNumeric &operator%=(Src rhs);
143 
145  {
147  T value = CheckedNeg(state_.value(), &validity);
148  // Negation is always valid for floating point.
149  if (std::numeric_limits<T>::is_iec559)
150  return CheckedNumeric<T>(value);
151 
152  validity = GetRangeConstraint(state_.validity() | validity);
154  }
155 
157  {
159  T value = CheckedAbs(state_.value(), &validity);
160  // Absolute value is always valid for floating point.
161  if (std::numeric_limits<T>::is_iec559)
162  return CheckedNumeric<T>(value);
163 
164  validity = GetRangeConstraint(state_.validity() | validity);
166  }
167 
168  // This function is available only for integral types. It returns an unsigned
169  // integer of the same width as the source type, containing the absolute value
170  // of the source, and properly handling signed min.
172  {
174  CheckedUnsignedAbs(state_.value()), state_.validity());
175  }
176 
178  {
179  *this += 1;
180  return *this;
181  }
182 
184  {
185  CheckedNumeric value = *this;
186  *this += 1;
187  return value;
188  }
189 
191  {
192  *this -= 1;
193  return *this;
194  }
195 
197  {
198  CheckedNumeric value = *this;
199  *this -= 1;
200  return value;
201  }
202 
203  // These static methods behave like a convenience cast operator targeting
204  // the desired CheckedNumeric type. As an optimization, a reference is
205  // returned when Src is the same type as T.
206  template <typename Src>
208  Src u,
209  typename std::enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 0)
210  {
211  return u;
212  }
213 
214  template <typename Src>
216  const CheckedNumeric<Src> &u,
217  typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0)
218  {
219  return u;
220  }
221 
222  static const CheckedNumeric<T> &cast(const CheckedNumeric<T> &u) { return u; }
223 
224  private:
225  template <typename NumericType>
226  struct UnderlyingType
227  {
228  using type = NumericType;
229  };
230 
231  template <typename NumericType>
232  struct UnderlyingType<CheckedNumeric<NumericType>>
233  {
234  using type = NumericType;
235  };
236 
237  CheckedNumericState<T> state_;
238 };
239 
240 // This is the boilerplate for the standard arithmetic operator overloads. A
241 // macro isn't the prettiest solution, but it beats rewriting these five times.
242 // Some details worth noting are:
243 // * We apply the standard arithmetic promotions.
244 // * We skip range checks for floating points.
245 // * We skip range checks for destination integers with sufficient range.
246 // TODO(jschuh): extract these out into templates.
247 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
248  /* Binary arithmetic operator for CheckedNumerics of the same type. */ \
249  template <typename T> \
250  CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \
251  const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) \
252  { \
253  typedef typename ArithmeticPromotion<T>::type Promotion; \
254  /* Floating point always takes the fast path */ \
255  if (std::numeric_limits<T>::is_iec559) \
256  return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \
257  if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \
258  return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
259  GetRangeConstraint(rhs.validity() | lhs.validity())); \
260  RangeConstraint validity = RANGE_VALID; \
261  T result = \
262  static_cast<T>(Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \
263  static_cast<Promotion>(rhs.ValueUnsafe()), &validity)); \
264  return CheckedNumeric<Promotion>( \
265  result, GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \
266  } \
267  /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
268  template <typename T> \
269  template <typename Src> \
270  CheckedNumeric<T> &CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) \
271  { \
272  *this = CheckedNumeric<T>::cast(*this) \
273  OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \
274  return *this; \
275  } \
276  /* Binary arithmetic operator for CheckedNumeric of different type. */ \
277  template <typename T, typename Src> \
278  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
279  const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) \
280  { \
281  typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
282  if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
283  return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
284  GetRangeConstraint(rhs.validity() | lhs.validity())); \
285  return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \
286  } \
287  /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
288  template <typename T, typename Src, \
289  typename std::enable_if<std::is_arithmetic<Src>::value>::type * = nullptr> \
290  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
291  const CheckedNumeric<T> &lhs, Src rhs) \
292  { \
293  typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
294  if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
295  return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, lhs.validity()); \
296  return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \
297  } \
298  /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \
299  template <typename T, typename Src, \
300  typename std::enable_if<std::is_arithmetic<Src>::value>::type * = nullptr> \
301  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
302  Src lhs, const CheckedNumeric<T> &rhs) \
303  { \
304  typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
305  if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
306  return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), rhs.validity()); \
307  return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \
308  }
309 
315 
316 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
317 
318 } // namespace internal
319 
320 using internal::CheckedNumeric;
321 
322 } // namespace base
323 
324 #endif // BASE_NUMERICS_SAFE_MATH_H_
RangeConstraint
Definition: safe_conversions_impl.h:95
CheckedNumeric & operator++()
Definition: safe_math.h:177
CheckedNumeric operator++(int)
Definition: safe_math.h:183
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:398
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)
Definition: safe_math.h:247
T ValueOrDefault(T default_value) const
Definition: safe_math.h:103
CheckedNumeric< typename UnsignedOrFloatForSize< T >::type > UnsignedAbs() const
Definition: safe_math.h:171
CheckedNumeric & operator+=(Src rhs)
CheckedNumeric operator-() const
Definition: safe_math.h:144
T ValueFloating() const
Definition: safe_math.h:108
CheckedNumeric operator--(int)
Definition: safe_math.h:196
std::enable_if< std::numeric_limits< T >::is_integer &&std::numeric_limits< T >::is_signed, T >::type CheckedAbs(T value, RangeConstraint *validity)
Definition: safe_math_impl.h:326
std::enable_if< std::numeric_limits< T >::is_integer &&std::numeric_limits< T >::is_signed, T >::type CheckedNeg(T value, RangeConstraint *validity)
Definition: safe_math_impl.h:306
TestSubObjConstructor T
Definition: TestTypedefs.idl:84
CheckedNumeric & operator-=(Src rhs)
CheckedNumeric Abs() const
Definition: safe_math.h:156
static const CheckedNumeric< T > & cast(const CheckedNumeric< T > &u)
Definition: safe_math.h:222
EGLAttrib * value
Definition: eglext.h:120
CheckedNumeric(StrictNumeric< Src > value)
Definition: safe_math.h:84
Definition: safe_math.h:52
std::enable_if< std::numeric_limits< T >::is_integer &&std::numeric_limits< T >::is_signed, typename UnsignedIntegerForSize< T >::type >::type CheckedUnsignedAbs(T value)
Definition: safe_math_impl.h:345
T ValueOrDie() const
Definition: safe_math.h:94
static CheckedNumeric< T > cast(const CheckedNumeric< Src > &u, typename std::enable_if<!std::is_same< Src, T >::value, int >::type=0)
Definition: safe_math.h:215
CheckedNumeric(const CheckedNumeric< Src > &rhs)
Definition: safe_math.h:63
Definition: safe_conversions.h:138
CheckedNumeric()
Definition: safe_math.h:59
Definition: safe_conversions.h:16
Definition: document.h:393
RangeConstraint validity() const
Definition: safe_math.h:121
T ValueUnsafe() const
Definition: safe_math.h:130
CheckedNumeric & operator/=(Src rhs)
T type
Definition: safe_math.h:54
#define CHECK(x)
Definition: dynbench.cpp:46
bool IsValid() const
Definition: safe_math.h:90
CheckedNumeric(Src value)
Definition: safe_math.h:75
CheckedNumeric(Src value, RangeConstraint validity)
Definition: safe_math.h:68
static CheckedNumeric< T > cast(Src u, typename std::enable_if< std::numeric_limits< Src >::is_specialized, int >::type=0)
Definition: safe_math.h:207
Definition: safe_conversions_impl.h:97
CheckedNumeric & operator*=(Src rhs)
CheckedNumeric & operator--()
Definition: safe_math.h:190
constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint)
Definition: safe_conversions_impl.h:104
CheckedNumeric & operator%=(Src rhs)