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