1 // Copyright 2017 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_CHECKED_MATH_H_ 6 #define BASE_NUMERICS_CHECKED_MATH_H_ 7 8 #include <stddef.h> 9 10 #include <limits> 11 #include <type_traits> 12 13 #include "base/numerics/checked_math_impl.h" 14 15 namespace base { 16 namespace internal { 17 18 template <typename T> 19 class CheckedNumeric { 20 static_assert(std::is_arithmetic<T>::value, 21 "CheckedNumeric<T>: T must be a numeric type."); 22 23 public: 24 using type = T; 25 26 constexpr CheckedNumeric() = default; 27 28 // Copy constructor. 29 template <typename Src> CheckedNumeric(const CheckedNumeric<Src> & rhs)30 constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs) 31 : state_(rhs.state_.value(), rhs.IsValid()) {} 32 33 template <typename Src> 34 friend class CheckedNumeric; 35 36 // This is not an explicit constructor because we implicitly upgrade regular 37 // numerics to CheckedNumerics to make them easier to use. 38 template <typename Src> CheckedNumeric(Src value)39 constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) 40 : state_(value) { 41 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); 42 } 43 44 // This is not an explicit constructor because we want a seamless conversion 45 // from StrictNumeric types. 46 template <typename Src> CheckedNumeric(StrictNumeric<Src> value)47 constexpr CheckedNumeric( 48 StrictNumeric<Src> value) // NOLINT(runtime/explicit) 49 : state_(static_cast<Src>(value)) {} 50 51 // IsValid() - The public API to test if a CheckedNumeric is currently valid. 52 // A range checked destination type can be supplied using the Dst template 53 // parameter. 54 template <typename Dst = T> IsValid()55 constexpr bool IsValid() const { 56 return state_.is_valid() && 57 IsValueInRangeForNumericType<Dst>(state_.value()); 58 } 59 60 // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid 61 // and is within the range supported by the destination type. Returns true if 62 // successful and false otherwise. 63 template <typename Dst> 64 #if defined(__clang__) || defined(__GNUC__) 65 __attribute__((warn_unused_result)) 66 #elif defined(_MSC_VER) 67 _Check_return_ 68 #endif 69 constexpr bool AssignIfValid(Dst * result)70 AssignIfValid(Dst* result) const { 71 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 72 ? ((*result = static_cast<Dst>(state_.value())), true) 73 : false; 74 } 75 76 // ValueOrDie() - The primary accessor for the underlying value. If the 77 // current state is not valid it will CHECK and crash. 78 // A range checked destination type can be supplied using the Dst template 79 // parameter, which will trigger a CHECK if the value is not in bounds for 80 // the destination. 81 // The CHECK behavior can be overridden by supplying a handler as a 82 // template parameter, for test code, etc. However, the handler cannot access 83 // the underlying value, and it is not available through other means. 84 template <typename Dst = T, class CheckHandler = CheckOnFailure> ValueOrDie()85 constexpr StrictNumeric<Dst> ValueOrDie() const { 86 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 87 ? static_cast<Dst>(state_.value()) 88 : CheckHandler::template HandleFailure<Dst>(); 89 } 90 91 // ValueOrDefault(T default_value) - A convenience method that returns the 92 // current value if the state is valid, and the supplied default_value for 93 // any other state. 94 // A range checked destination type can be supplied using the Dst template 95 // parameter. WARNING: This function may fail to compile or CHECK at runtime 96 // if the supplied default_value is not within range of the destination type. 97 template <typename Dst = T, typename Src> ValueOrDefault(const Src default_value)98 constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const { 99 return BASE_NUMERICS_LIKELY(IsValid<Dst>()) 100 ? static_cast<Dst>(state_.value()) 101 : checked_cast<Dst>(default_value); 102 } 103 104 // Returns a checked numeric of the specified type, cast from the current 105 // CheckedNumeric. If the current state is invalid or the destination cannot 106 // represent the result then the returned CheckedNumeric will be invalid. 107 template <typename Dst> Cast()108 constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const { 109 return *this; 110 } 111 112 // This friend method is available solely for providing more detailed logging 113 // in the the tests. Do not implement it in production code, because the 114 // underlying values may change at any time. 115 template <typename U> 116 friend U GetNumericValueForTest(const CheckedNumeric<U>& src); 117 118 // Prototypes for the supported arithmetic operator overloads. 119 template <typename Src> 120 constexpr CheckedNumeric& operator+=(const Src rhs); 121 template <typename Src> 122 constexpr CheckedNumeric& operator-=(const Src rhs); 123 template <typename Src> 124 constexpr CheckedNumeric& operator*=(const Src rhs); 125 template <typename Src> 126 constexpr CheckedNumeric& operator/=(const Src rhs); 127 template <typename Src> 128 constexpr CheckedNumeric& operator%=(const Src rhs); 129 template <typename Src> 130 constexpr CheckedNumeric& operator<<=(const Src rhs); 131 template <typename Src> 132 constexpr CheckedNumeric& operator>>=(const Src rhs); 133 template <typename Src> 134 constexpr CheckedNumeric& operator&=(const Src rhs); 135 template <typename Src> 136 constexpr CheckedNumeric& operator|=(const Src rhs); 137 template <typename Src> 138 constexpr CheckedNumeric& operator^=(const Src rhs); 139 140 constexpr CheckedNumeric operator-() const { 141 // The negation of two's complement int min is int min, so we simply 142 // check for that in the constexpr case. 143 // We use an optimized code path for a known run-time variable. 144 return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value || 145 std::is_floating_point<T>::value 146 ? CheckedNumeric<T>( 147 NegateWrapper(state_.value()), 148 IsValid() && (!std::is_signed<T>::value || 149 std::is_floating_point<T>::value || 150 NegateWrapper(state_.value()) != 151 std::numeric_limits<T>::lowest())) 152 : FastRuntimeNegate(); 153 } 154 155 constexpr CheckedNumeric operator~() const { 156 return CheckedNumeric<decltype(InvertWrapper(T()))>( 157 InvertWrapper(state_.value()), IsValid()); 158 } 159 Abs()160 constexpr CheckedNumeric Abs() const { 161 return !IsValueNegative(state_.value()) ? *this : -*this; 162 } 163 164 template <typename U> Max(const U rhs)165 constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max( 166 const U rhs) const { 167 using R = typename UnderlyingType<U>::type; 168 using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type; 169 // TODO(jschuh): This can be converted to the MathOp version and remain 170 // constexpr once we have C++14 support. 171 return CheckedNumeric<result_type>( 172 static_cast<result_type>( 173 IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 174 ? state_.value() 175 : Wrapper<U>::value(rhs)), 176 state_.is_valid() && Wrapper<U>::is_valid(rhs)); 177 } 178 179 template <typename U> Min(const U rhs)180 constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min( 181 const U rhs) const { 182 using R = typename UnderlyingType<U>::type; 183 using result_type = typename MathWrapper<CheckedMinOp, T, U>::type; 184 // TODO(jschuh): This can be converted to the MathOp version and remain 185 // constexpr once we have C++14 support. 186 return CheckedNumeric<result_type>( 187 static_cast<result_type>( 188 IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs)) 189 ? state_.value() 190 : Wrapper<U>::value(rhs)), 191 state_.is_valid() && Wrapper<U>::is_valid(rhs)); 192 } 193 194 // This function is available only for integral types. It returns an unsigned 195 // integer of the same width as the source type, containing the absolute value 196 // of the source, and properly handling signed min. 197 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs()198 UnsignedAbs() const { 199 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 200 SafeUnsignedAbs(state_.value()), state_.is_valid()); 201 } 202 203 constexpr CheckedNumeric& operator++() { 204 *this += 1; 205 return *this; 206 } 207 208 constexpr CheckedNumeric operator++(int) { 209 CheckedNumeric value = *this; 210 *this += 1; 211 return value; 212 } 213 214 constexpr CheckedNumeric& operator--() { 215 *this -= 1; 216 return *this; 217 } 218 219 constexpr CheckedNumeric operator--(int) { 220 CheckedNumeric value = *this; 221 *this -= 1; 222 return value; 223 } 224 225 // These perform the actual math operations on the CheckedNumerics. 226 // Binary arithmetic operations. 227 template <template <typename, typename, typename> class M, 228 typename L, 229 typename R> MathOp(const L lhs,const R rhs)230 static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) { 231 using Math = typename MathWrapper<M, L, R>::math; 232 T result = 0; 233 bool is_valid = 234 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 235 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 236 return CheckedNumeric<T>(result, is_valid); 237 } 238 239 // Assignment arithmetic operations. 240 template <template <typename, typename, typename> class M, typename R> MathOp(const R rhs)241 constexpr CheckedNumeric& MathOp(const R rhs) { 242 using Math = typename MathWrapper<M, T, R>::math; 243 T result = 0; // Using T as the destination saves a range check. 244 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) && 245 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 246 *this = CheckedNumeric<T>(result, is_valid); 247 return *this; 248 } 249 250 private: 251 CheckedNumericState<T> state_; 252 FastRuntimeNegate()253 CheckedNumeric FastRuntimeNegate() const { 254 T result; 255 bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result); 256 return CheckedNumeric<T>(result, IsValid() && success); 257 } 258 259 template <typename Src> CheckedNumeric(Src value,bool is_valid)260 constexpr CheckedNumeric(Src value, bool is_valid) 261 : state_(value, is_valid) {} 262 263 // These wrappers allow us to handle state the same way for both 264 // CheckedNumeric and POD arithmetic types. 265 template <typename Src> 266 struct Wrapper { is_validWrapper267 static constexpr bool is_valid(Src) { return true; } valueWrapper268 static constexpr Src value(Src value) { return value; } 269 }; 270 271 template <typename Src> 272 struct Wrapper<CheckedNumeric<Src>> { 273 static constexpr bool is_valid(const CheckedNumeric<Src> v) { 274 return v.IsValid(); 275 } 276 static constexpr Src value(const CheckedNumeric<Src> v) { 277 return v.state_.value(); 278 } 279 }; 280 281 template <typename Src> 282 struct Wrapper<StrictNumeric<Src>> { 283 static constexpr bool is_valid(const StrictNumeric<Src>) { return true; } 284 static constexpr Src value(const StrictNumeric<Src> v) { 285 return static_cast<Src>(v); 286 } 287 }; 288 }; 289 290 // Convenience functions to avoid the ugly template disambiguator syntax. 291 template <typename Dst, typename Src> 292 constexpr bool IsValidForType(const CheckedNumeric<Src> value) { 293 return value.template IsValid<Dst>(); 294 } 295 296 template <typename Dst, typename Src> 297 constexpr StrictNumeric<Dst> ValueOrDieForType( 298 const CheckedNumeric<Src> value) { 299 return value.template ValueOrDie<Dst>(); 300 } 301 302 template <typename Dst, typename Src, typename Default> 303 constexpr StrictNumeric<Dst> ValueOrDefaultForType( 304 const CheckedNumeric<Src> value, 305 const Default default_value) { 306 return value.template ValueOrDefault<Dst>(default_value); 307 } 308 309 // Convience wrapper to return a new CheckedNumeric from the provided arithmetic 310 // or CheckedNumericType. 311 template <typename T> 312 constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum( 313 const T value) { 314 return value; 315 } 316 317 // These implement the variadic wrapper for the math operations. 318 template <template <typename, typename, typename> class M, 319 typename L, 320 typename R> 321 constexpr CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp( 322 const L lhs, 323 const R rhs) { 324 using Math = typename MathWrapper<M, L, R>::math; 325 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 326 rhs); 327 } 328 329 // General purpose wrapper template for arithmetic operations. 330 template <template <typename, typename, typename> class M, 331 typename L, 332 typename R, 333 typename... Args> 334 constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type> 335 CheckMathOp(const L lhs, const R rhs, const Args... args) { 336 return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...); 337 } 338 339 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=) 340 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=) 341 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=) 342 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=) 343 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=) 344 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=) 345 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=) 346 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=) 347 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=) 348 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=) 349 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max) 350 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min) 351 352 // These are some extra StrictNumeric operators to support simple pointer 353 // arithmetic with our result types. Since wrapping on a pointer is always 354 // bad, we trigger the CHECK condition here. 355 template <typename L, typename R> 356 L* operator+(L* lhs, const StrictNumeric<R> rhs) { 357 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 358 CheckMul(sizeof(L), static_cast<R>(rhs))) 359 .template ValueOrDie<uintptr_t>(); 360 return reinterpret_cast<L*>(result); 361 } 362 363 template <typename L, typename R> 364 L* operator-(L* lhs, const StrictNumeric<R> rhs) { 365 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs), 366 CheckMul(sizeof(L), static_cast<R>(rhs))) 367 .template ValueOrDie<uintptr_t>(); 368 return reinterpret_cast<L*>(result); 369 } 370 371 } // namespace internal 372 373 using internal::CheckedNumeric; 374 using internal::IsValidForType; 375 using internal::ValueOrDieForType; 376 using internal::ValueOrDefaultForType; 377 using internal::MakeCheckedNum; 378 using internal::CheckMax; 379 using internal::CheckMin; 380 using internal::CheckAdd; 381 using internal::CheckSub; 382 using internal::CheckMul; 383 using internal::CheckDiv; 384 using internal::CheckMod; 385 using internal::CheckLsh; 386 using internal::CheckRsh; 387 using internal::CheckAnd; 388 using internal::CheckOr; 389 using internal::CheckXor; 390 391 } // namespace base 392 393 #endif // BASE_NUMERICS_CHECKED_MATH_H_ 394