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 <stdint.h> 9 10 #include <limits> 11 #include <type_traits> 12 13 #include "base/numerics/checked_math_impl.h" // IWYU pragma: export 14 #include "base/numerics/safe_conversions.h" 15 #include "base/numerics/safe_math_shared_impl.h" // IWYU pragma: export 16 17 namespace base { 18 namespace internal { 19 20 template <typename T> 21 requires std::is_arithmetic_v<T> 22 class CheckedNumeric { 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 // This is not an explicit constructor because we implicitly upgrade regular 34 // numerics to CheckedNumerics to make them easier to use. 35 template <typename Src> requires(std::is_arithmetic_v<Src>)36 requires(std::is_arithmetic_v<Src>) 37 // NOLINTNEXTLINE(google-explicit-constructor) 38 constexpr CheckedNumeric(Src value) : state_(value) {} 39 40 // This is not an explicit constructor because we want a seamless conversion 41 // from StrictNumeric types. 42 template <typename Src> 43 // NOLINTNEXTLINE(google-explicit-constructor) CheckedNumeric(StrictNumeric<Src> value)44 constexpr CheckedNumeric(StrictNumeric<Src> value) 45 : state_(static_cast<Src>(value)) {} 46 47 // IsValid() - The public API to test if a CheckedNumeric is currently valid. 48 // A range checked destination type can be supplied using the Dst template 49 // parameter. 50 template <typename Dst = T> IsValid()51 constexpr bool IsValid() const { 52 return state_.is_valid() && 53 IsValueInRangeForNumericType<Dst>(state_.value()); 54 } 55 56 // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid 57 // and is within the range supported by the destination type. Returns true if 58 // successful and false otherwise. 59 template <typename Dst> 60 #if defined(__clang__) || defined(__GNUC__) 61 __attribute__((warn_unused_result)) 62 #elif defined(_MSC_VER) 63 _Check_return_ 64 #endif 65 constexpr bool AssignIfValid(Dst * result)66 AssignIfValid(Dst* result) const { 67 if (IsValid<Dst>()) [[likely]] { 68 *result = static_cast<Dst>(state_.value()); 69 return true; 70 } 71 return false; 72 } 73 74 // ValueOrDie() - The primary accessor for the underlying value. If the 75 // current state is not valid it will CHECK and crash. 76 // A range checked destination type can be supplied using the Dst template 77 // parameter, which will trigger a CHECK if the value is not in bounds for 78 // the destination. 79 // The CHECK behavior can be overridden by supplying a handler as a 80 // template parameter, for test code, etc. However, the handler cannot access 81 // the underlying value, and it is not available through other means. 82 template <typename Dst = T, class CheckHandler = CheckOnFailure> ValueOrDie()83 constexpr StrictNumeric<Dst> ValueOrDie() const { 84 if (IsValid<Dst>()) [[likely]] { 85 return static_cast<Dst>(state_.value()); 86 } 87 return CheckHandler::template HandleFailure<Dst>(); 88 } 89 90 // ValueOrDefault(T default_value) - A convenience method that returns the 91 // current value if the state is valid, and the supplied default_value for 92 // any other state. 93 // A range checked destination type can be supplied using the Dst template 94 // parameter. WARNING: This function may fail to compile or CHECK at runtime 95 // if the supplied default_value is not within range of the destination type. 96 template <typename Dst = T, typename Src> ValueOrDefault(Src default_value)97 constexpr StrictNumeric<Dst> ValueOrDefault(Src default_value) const { 98 if (IsValid<Dst>()) [[likely]] { 99 return static_cast<Dst>(state_.value()); 100 } 101 return 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 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 // Use an optimized code path for a known run-time variable. 142 if (!std::is_constant_evaluated() && std::is_signed_v<T> && 143 std::is_floating_point_v<T>) { 144 return FastRuntimeNegate(); 145 } 146 // The negation of two's complement int min is int min. 147 const bool is_valid = 148 IsValid() && 149 (!std::is_signed_v<T> || std::is_floating_point_v<T> || 150 NegateWrapper(state_.value()) != std::numeric_limits<T>::lowest()); 151 return CheckedNumeric<T>(NegateWrapper(state_.value()), is_valid); 152 } 153 154 constexpr CheckedNumeric operator~() const { 155 return CheckedNumeric<decltype(InvertWrapper(T()))>( 156 InvertWrapper(state_.value()), IsValid()); 157 } 158 Abs()159 constexpr CheckedNumeric Abs() const { 160 return !IsValueNegative(state_.value()) ? *this : -*this; 161 } 162 163 template <typename U> Max(U rhs)164 constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max( 165 U rhs) const { 166 return CheckMax(*this, rhs); 167 } 168 169 template <typename U> Min(U rhs)170 constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min( 171 U rhs) const { 172 return CheckMin(*this, rhs); 173 } 174 175 // This function is available only for integral types. It returns an unsigned 176 // integer of the same width as the source type, containing the absolute value 177 // of the source, and properly handling signed min. 178 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs()179 UnsignedAbs() const { 180 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 181 SafeUnsignedAbs(state_.value()), state_.is_valid()); 182 } 183 184 constexpr CheckedNumeric& operator++() { 185 *this += 1; 186 return *this; 187 } 188 189 constexpr CheckedNumeric operator++(int) { 190 const CheckedNumeric value = *this; 191 ++*this; 192 return value; 193 } 194 195 constexpr CheckedNumeric& operator--() { 196 *this -= 1; 197 return *this; 198 } 199 200 constexpr CheckedNumeric operator--(int) { 201 const CheckedNumeric value = *this; 202 --*this; 203 return value; 204 } 205 206 // These perform the actual math operations on the CheckedNumerics. 207 // Binary arithmetic operations. 208 template <template <typename, typename> class M, typename L, typename R> MathOp(L lhs,R rhs)209 static constexpr CheckedNumeric MathOp(L lhs, R rhs) { 210 using Math = typename MathWrapper<M, L, R>::math; 211 T result = 0; 212 const bool is_valid = 213 Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && 214 Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); 215 return CheckedNumeric<T>(result, is_valid); 216 } 217 218 // Assignment arithmetic operations. 219 template <template <typename, typename> class M, typename R> MathOp(R rhs)220 constexpr CheckedNumeric& MathOp(R rhs) { 221 using Math = typename MathWrapper<M, T, R>::math; 222 T result = 0; // Using T as the destination saves a range check. 223 const bool is_valid = 224 state_.is_valid() && Wrapper<R>::is_valid(rhs) && 225 Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); 226 *this = CheckedNumeric<T>(result, is_valid); 227 return *this; 228 } 229 230 private: 231 template <typename U> 232 requires std::is_arithmetic_v<U> 233 friend class CheckedNumeric; 234 235 CheckedNumericState<T> state_; 236 FastRuntimeNegate()237 CheckedNumeric FastRuntimeNegate() const { 238 T result; 239 const bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result); 240 return CheckedNumeric<T>(result, IsValid() && success); 241 } 242 243 template <typename Src> CheckedNumeric(Src value,bool is_valid)244 constexpr CheckedNumeric(Src value, bool is_valid) 245 : state_(value, is_valid) {} 246 247 // These wrappers allow us to handle state the same way for both 248 // CheckedNumeric and POD arithmetic types. 249 template <typename Src> 250 struct Wrapper { is_validWrapper251 static constexpr bool is_valid(Src) { return true; } valueWrapper252 static constexpr Src value(Src value) { return value; } 253 }; 254 255 template <typename Src> 256 struct Wrapper<CheckedNumeric<Src>> { 257 static constexpr bool is_valid(CheckedNumeric<Src> v) { 258 return v.IsValid(); 259 } 260 static constexpr Src value(CheckedNumeric<Src> v) { 261 return v.state_.value(); 262 } 263 }; 264 265 template <typename Src> 266 struct Wrapper<StrictNumeric<Src>> { 267 static constexpr bool is_valid(StrictNumeric<Src>) { return true; } 268 static constexpr Src value(StrictNumeric<Src> v) { 269 return static_cast<Src>(v); 270 } 271 }; 272 }; 273 274 template <typename T> 275 CheckedNumeric(T) -> CheckedNumeric<T>; 276 277 // Convenience functions to avoid the ugly template disambiguator syntax. 278 template <typename Dst, typename Src> 279 constexpr bool IsValidForType(const CheckedNumeric<Src> value) { 280 return value.template IsValid<Dst>(); 281 } 282 283 template <typename Dst, typename Src> 284 constexpr StrictNumeric<Dst> ValueOrDieForType( 285 const CheckedNumeric<Src> value) { 286 return value.template ValueOrDie<Dst>(); 287 } 288 289 template <typename Dst, typename Src, typename Default> 290 constexpr StrictNumeric<Dst> ValueOrDefaultForType(CheckedNumeric<Src> value, 291 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 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 L lhs, 307 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(L lhs, R rhs, 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, 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, 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