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_v<T>, 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> requires(std::is_arithmetic_v<Src>)45 requires(std::is_arithmetic_v<Src>) 46 // NOLINTNEXTLINE(google-explicit-constructor) 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_v<T> && 148 std::is_floating_point_v<T>) { 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_v<T> || std::is_floating_point_v<T> || 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> class M, typename L, typename R> MathOp(const L lhs,const R rhs)215 static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) { 216 using Math = typename MathWrapper<M, L, R>::math; 217 T result = 0; 218 const bool is_valid = 219 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 220 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 221 return CheckedNumeric<T>(result, is_valid); 222 } 223 224 // Assignment arithmetic operations. 225 template <template <typename, typename> class M, typename R> MathOp(const R rhs)226 constexpr CheckedNumeric& MathOp(const R rhs) { 227 using Math = typename MathWrapper<M, T, R>::math; 228 T result = 0; // Using T as the destination saves a range check. 229 const bool is_valid = 230 state_.is_valid() && Wrapper<R>::is_valid(rhs) && 231 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 232 *this = CheckedNumeric<T>(result, is_valid); 233 return *this; 234 } 235 236 private: 237 CheckedNumericState<T> state_; 238 FastRuntimeNegate()239 CheckedNumeric FastRuntimeNegate() const { 240 T result; 241 const bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result); 242 return CheckedNumeric<T>(result, IsValid() && success); 243 } 244 245 template <typename Src> CheckedNumeric(Src value,bool is_valid)246 constexpr CheckedNumeric(Src value, bool is_valid) 247 : state_(value, is_valid) {} 248 249 // These wrappers allow us to handle state the same way for both 250 // CheckedNumeric and POD arithmetic types. 251 template <typename Src> 252 struct Wrapper { is_validWrapper253 static constexpr bool is_valid(Src) { return true; } valueWrapper254 static constexpr Src value(Src value) { return value; } 255 }; 256 257 template <typename Src> 258 struct Wrapper<CheckedNumeric<Src>> { 259 static constexpr bool is_valid(const CheckedNumeric<Src> v) { 260 return v.IsValid(); 261 } 262 static constexpr Src value(const CheckedNumeric<Src> v) { 263 return v.state_.value(); 264 } 265 }; 266 267 template <typename Src> 268 struct Wrapper<StrictNumeric<Src>> { 269 static constexpr bool is_valid(const StrictNumeric<Src>) { return true; } 270 static constexpr Src value(const StrictNumeric<Src> v) { 271 return static_cast<Src>(v); 272 } 273 }; 274 }; 275 276 // Convenience functions to avoid the ugly template disambiguator syntax. 277 template <typename Dst, typename Src> 278 constexpr bool IsValidForType(const CheckedNumeric<Src> value) { 279 return value.template IsValid<Dst>(); 280 } 281 282 template <typename Dst, typename Src> 283 constexpr StrictNumeric<Dst> ValueOrDieForType( 284 const CheckedNumeric<Src> value) { 285 return value.template ValueOrDie<Dst>(); 286 } 287 288 template <typename Dst, typename Src, typename Default> 289 constexpr StrictNumeric<Dst> ValueOrDefaultForType( 290 const CheckedNumeric<Src> value, 291 const Default default_value) { 292 return value.template ValueOrDefault<Dst>(default_value); 293 } 294 295 // Convenience wrapper to return a new CheckedNumeric from the provided 296 // arithmetic or CheckedNumericType. 297 template <typename T> 298 constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum( 299 const T value) { 300 return value; 301 } 302 303 // These implement the variadic wrapper for the math operations. 304 template <template <typename, typename> class M, typename L, typename R> 305 constexpr CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp( 306 const L lhs, 307 const R rhs) { 308 using Math = typename MathWrapper<M, L, R>::math; 309 return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs, 310 rhs); 311 } 312 313 // General purpose wrapper template for arithmetic operations. 314 template <template <typename, typename> class M, 315 typename L, 316 typename R, 317 typename... Args> 318 constexpr auto CheckMathOp(const L lhs, const R rhs, const Args... args) { 319 return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...); 320 } 321 322 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=) 323 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=) 324 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=) 325 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=) 326 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=) 327 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=) 328 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=) 329 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=) 330 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=) 331 BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=) 332 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max) 333 BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min) 334 335 // These are some extra StrictNumeric operators to support simple pointer 336 // arithmetic with our result types. Since wrapping on a pointer is always 337 // bad, we trigger the CHECK condition here. 338 template <typename L, typename R> 339 L* operator+(L* lhs, const StrictNumeric<R> rhs) { 340 const uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs), 341 CheckMul(sizeof(L), static_cast<R>(rhs))) 342 .template ValueOrDie<uintptr_t>(); 343 return reinterpret_cast<L*>(result); 344 } 345 346 template <typename L, typename R> 347 L* operator-(L* lhs, const StrictNumeric<R> rhs) { 348 const uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs), 349 CheckMul(sizeof(L), static_cast<R>(rhs))) 350 .template ValueOrDie<uintptr_t>(); 351 return reinterpret_cast<L*>(result); 352 } 353 354 } // namespace internal 355 356 using internal::CheckAdd; 357 using internal::CheckAnd; 358 using internal::CheckDiv; 359 using internal::CheckedNumeric; 360 using internal::CheckLsh; 361 using internal::CheckMax; 362 using internal::CheckMin; 363 using internal::CheckMod; 364 using internal::CheckMul; 365 using internal::CheckOr; 366 using internal::CheckRsh; 367 using internal::CheckSub; 368 using internal::CheckXor; 369 using internal::IsValidForType; 370 using internal::MakeCheckedNum; 371 using internal::ValueOrDefaultForType; 372 using internal::ValueOrDieForType; 373 374 } // namespace base 375 376 #endif // BASE_NUMERICS_CHECKED_MATH_H_ 377