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