| 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 ANGLEBASE_NUMERICS_SAFE_MATH_H_ |
| 6 | #define ANGLEBASE_NUMERICS_SAFE_MATH_H_ |
| 7 | |
| 8 | #include <stddef.h> |
| 9 | |
| 10 | #include <limits> |
| 11 | #include <type_traits> |
| 12 | |
| 13 | #include "anglebase/logging.h" |
| 14 | #include "anglebase/numerics/safe_math_impl.h" |
| 15 | |
| 16 | namespace angle |
| 17 | { |
| 18 | |
| 19 | namespace base |
| 20 | { |
| 21 | |
| 22 | namespace internal |
| 23 | { |
| 24 | |
| 25 | // CheckedNumeric implements all the logic and operators for detecting integer |
| 26 | // boundary conditions such as overflow, underflow, and invalid conversions. |
| 27 | // The CheckedNumeric type implicitly converts from floating point and integer |
| 28 | // data types, and contains overloads for basic arithmetic operations (i.e.: +, |
| 29 | // -, *, /, %). |
| 30 | // |
| 31 | // The following methods convert from CheckedNumeric to standard numeric values: |
| 32 | // IsValid() - Returns true if the underlying numeric value is valid (i.e. has |
| 33 | // has not wrapped and is not the result of an invalid conversion). |
| 34 | // ValueOrDie() - Returns the underlying value. If the state is not valid this |
| 35 | // call will crash on a CHECK. |
| 36 | // ValueOrDefault() - Returns the current value, or the supplied default if the |
| 37 | // state is not valid. |
| 38 | // ValueFloating() - Returns the underlying floating point value (valid only |
| 39 | // only for floating point CheckedNumeric types). |
| 40 | // |
| 41 | // Bitwise operations are explicitly not supported, because correct |
| 42 | // handling of some cases (e.g. sign manipulation) is ambiguous. Comparison |
| 43 | // operations are explicitly not supported because they could result in a crash |
| 44 | // on a CHECK condition. You should use patterns like the following for these |
| 45 | // operations: |
| 46 | // Bitwise operation: |
| 47 | // CheckedNumeric<int> checked_int = untrusted_input_value; |
| 48 | // int x = checked_int.ValueOrDefault(0) | kFlagValues; |
| 49 | // Comparison: |
| 50 | // CheckedNumeric<size_t> checked_size = untrusted_input_value; |
| 51 | // checked_size += HEADER LENGTH; |
| 52 | // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) |
| 53 | // Do stuff... |
| 54 | template <typename T> |
| 55 | class CheckedNumeric |
| 56 | { |
| 57 | static_assert(std::is_arithmetic<T>::value, "CheckedNumeric<T>: T must be a numeric type." ); |
| 58 | |
| 59 | public: |
| 60 | typedef T type; |
| 61 | |
| 62 | CheckedNumeric() {} |
| 63 | |
| 64 | // Copy constructor. |
| 65 | template <typename Src> |
| 66 | CheckedNumeric(const CheckedNumeric<Src> &rhs) : state_(rhs.ValueUnsafe(), rhs.validity()) |
| 67 | {} |
| 68 | |
| 69 | template <typename Src> |
| 70 | CheckedNumeric(Src value, RangeConstraint validity) : state_(value, validity) |
| 71 | {} |
| 72 | |
| 73 | // This is not an explicit constructor because we implicitly upgrade regular |
| 74 | // numerics to CheckedNumerics to make them easier to use. |
| 75 | template <typename Src> |
| 76 | CheckedNumeric(Src value) // NOLINT(runtime/explicit) |
| 77 | : state_(value) |
| 78 | { |
| 79 | static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric." ); |
| 80 | } |
| 81 | |
| 82 | // This is not an explicit constructor because we want a seamless conversion |
| 83 | // from StrictNumeric types. |
| 84 | template <typename Src> |
| 85 | CheckedNumeric(StrictNumeric<Src> value) // NOLINT(runtime/explicit) |
| 86 | : state_(static_cast<Src>(value)) |
| 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 | |
| 144 | CheckedNumeric operator-() const |
| 145 | { |
| 146 | RangeConstraint validity; |
| 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); |
| 153 | return CheckedNumeric<T>(value, validity); |
| 154 | } |
| 155 | |
| 156 | CheckedNumeric Abs() const |
| 157 | { |
| 158 | RangeConstraint validity; |
| 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); |
| 165 | return CheckedNumeric<T>(value, 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. |
| 171 | CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const |
| 172 | { |
| 173 | return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( |
| 174 | CheckedUnsignedAbs(state_.value()), state_.validity()); |
| 175 | } |
| 176 | |
| 177 | CheckedNumeric &operator++() |
| 178 | { |
| 179 | *this += 1; |
| 180 | return *this; |
| 181 | } |
| 182 | |
| 183 | CheckedNumeric operator++(int) |
| 184 | { |
| 185 | CheckedNumeric value = *this; |
| 186 | *this += 1; |
| 187 | return value; |
| 188 | } |
| 189 | |
| 190 | CheckedNumeric &operator--() |
| 191 | { |
| 192 | *this -= 1; |
| 193 | return *this; |
| 194 | } |
| 195 | |
| 196 | CheckedNumeric operator--(int) |
| 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> |
| 207 | static CheckedNumeric<T> cast( |
| 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> |
| 215 | static CheckedNumeric<T> cast( |
| 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 ANGLEBASE_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 | |
| 310 | ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) |
| 311 | ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) |
| 312 | ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) |
| 313 | ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) |
| 314 | ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) |
| 315 | |
| 316 | #undef ANGLEBASE_NUMERIC_ARITHMETIC_OPERATORS |
| 317 | |
| 318 | } // namespace internal |
| 319 | |
| 320 | using internal::CheckedNumeric; |
| 321 | |
| 322 | } // namespace base |
| 323 | |
| 324 | } // namespace angle |
| 325 | |
| 326 | #endif // ANGLEBASE_NUMERICS_SAFE_MATH_H_ |
| 327 | |