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