// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_ #define PDFIUM_THIRD_PARTY_BASE_NUMERICS_SAFE_MATH_H_ #include #include #include #include "third_party/base/numerics/safe_math_impl.h" namespace pdfium { namespace base { namespace internal { // CheckedNumeric<> implements all the logic and operators for detecting integer // boundary conditions such as overflow, underflow, and invalid conversions. // The CheckedNumeric type implicitly converts from floating point and integer // data types, and contains overloads for basic arithmetic operations (i.e.: +, // -, *, / for all types and %, <<, >>, &, |, ^ for integers). Type promotions // are a slightly modified version of the standard C arithmetic rules with the // two differences being that there is no default promotion to int and bitwise // logical operations always return an unsigned of the wider type. // // You may also use one of the variadic convenience functions, which accept // standard arithmetic or CheckedNumeric types, perform arithmetic operations, // and return a CheckedNumeric result. The supported functions are: // CheckAdd() - Addition. // CheckSub() - Subtraction. // CheckMul() - Multiplication. // CheckDiv() - Division. // CheckMod() - Modulous (integer only). // CheckLsh() - Left integer shift (integer only). // CheckRsh() - Right integer shift (integer only). // CheckAnd() - Bitwise AND (integer only with unsigned result). // CheckOr() - Bitwise OR (integer only with unsigned result). // CheckXor() - Bitwise XOR (integer only with unsigned result). // CheckMax() - Maximum of supplied arguments. // CheckMin() - Minimum of supplied arguments. // // The unary negation, increment, and decrement operators are supported, along // with the following unary arithmetic methods, which return a new // CheckedNumeric as a result of the operation: // Abs() - Absolute value. // UnsignedAbs() - Absolute value as an equal-width unsigned underlying type // (valid for only integral types). // Max() - Returns whichever is greater of the current instance or argument. // The underlying return type is whichever has the greatest magnitude. // Min() - Returns whichever is lowest of the current instance or argument. // The underlying return type is whichever has can represent the lowest // number in the smallest width (e.g. int8_t over unsigned, int over // int8_t, and float over int). // // The following methods convert from CheckedNumeric to standard numeric values: // AssignIfValid() - Assigns the underlying value to the supplied destination // pointer if the value is currently valid and within the range // supported by the destination type. Returns true on success. // **************************************************************************** // * WARNING: All of the following functions return a StrictNumeric, which * // * is valid for comparison and assignment operations, but will trigger a * // * compile failure on attempts to assign to a type of insufficient range. * // **************************************************************************** // IsValid() - Returns true if the underlying numeric value is valid (i.e. has // has not wrapped and is not the result of an invalid conversion). // ValueOrDie() - Returns the underlying value. If the state is not valid this // call will crash on a CHECK. // ValueOrDefault() - Returns the current value, or the supplied default if the // state is not valid (will not trigger a CHECK). // // The following wrapper functions can be used to avoid the template // disambiguator syntax when converting a destination type. // IsValidForType<>() in place of: a.template IsValid() // ValueOrDieForType<>() in place of: a.template ValueOrDie() // ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default) // // The following are general utility methods that are useful for converting // between arithmetic types and CheckedNumeric types: // CheckedNumeric::Cast() - Instance method returning a CheckedNumeric // derived from casting the current instance to a CheckedNumeric of // the supplied destination type. // MakeCheckedNum() - Creates a new CheckedNumeric from the underlying type of // the supplied arithmetic, CheckedNumeric, or StrictNumeric type. // // Comparison operations are explicitly not supported because they could result // in a crash on an unexpected CHECK condition. You should use patterns like the // following for comparisons: // CheckedNumeric checked_size = untrusted_input_value; // checked_size += HEADER LENGTH; // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) // Do stuff... template class CheckedNumeric { static_assert(std::is_arithmetic::value, "CheckedNumeric: T must be a numeric type."); public: using type = T; constexpr CheckedNumeric() = default; // Copy constructor. template constexpr CheckedNumeric(const CheckedNumeric& rhs) : state_(rhs.state_.value(), rhs.IsValid()) {} template friend class CheckedNumeric; // This is not an explicit constructor because we implicitly upgrade regular // numerics to CheckedNumerics to make them easier to use. template constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) : state_(value) { static_assert(std::is_arithmetic::value, "Argument must be numeric."); } // This is not an explicit constructor because we want a seamless conversion // from StrictNumeric types. template constexpr CheckedNumeric( StrictNumeric value) // NOLINT(runtime/explicit) : state_(static_cast(value)) {} // IsValid() - The public API to test if a CheckedNumeric is currently valid. // A range checked destination type can be supplied using the Dst template // parameter. template constexpr bool IsValid() const { return state_.is_valid() && IsValueInRangeForNumericType(state_.value()); } // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid // and is within the range supported by the destination type. Returns true if // successful and false otherwise. template constexpr bool AssignIfValid(Dst* result) const { return IsValid() ? ((*result = static_cast(state_.value())), true) : false; } // ValueOrDie() - The primary accessor for the underlying value. If the // current state is not valid it will CHECK and crash. // A range checked destination type can be supplied using the Dst template // parameter, which will trigger a CHECK if the value is not in bounds for // the destination. // The CHECK behavior can be overridden by supplying a handler as a // template parameter, for test code, etc. However, the handler cannot access // the underlying value, and it is not available through other means. template constexpr StrictNumeric ValueOrDie() const { return IsValid() ? static_cast(state_.value()) : CheckHandler::template HandleFailure(); } // ValueOrDefault(T default_value) - A convenience method that returns the // current value if the state is valid, and the supplied default_value for // any other state. // A range checked destination type can be supplied using the Dst template // parameter. WARNING: This function may fail to compile or CHECK at runtime // if the supplied default_value is not within range of the destination type. template constexpr StrictNumeric ValueOrDefault(const Src default_value) const { return IsValid() ? static_cast(state_.value()) : checked_cast(default_value); } // Returns a checked numeric of the specified type, cast from the current // CheckedNumeric. If the current state is invalid or the destination cannot // represent the result then the returned CheckedNumeric will be invalid. template constexpr CheckedNumeric::type> Cast() const { return *this; } // This friend method is available solely for providing more detailed logging // in the the tests. Do not implement it in production code, because the // underlying values may change at any time. template friend U GetNumericValueForTest(const CheckedNumeric& src); // Prototypes for the supported arithmetic operator overloads. template CheckedNumeric& operator+=(const Src rhs); template CheckedNumeric& operator-=(const Src rhs); template CheckedNumeric& operator*=(const Src rhs); template CheckedNumeric& operator/=(const Src rhs); template CheckedNumeric& operator%=(const Src rhs); template CheckedNumeric& operator<<=(const Src rhs); template CheckedNumeric& operator>>=(const Src rhs); template CheckedNumeric& operator&=(const Src rhs); template CheckedNumeric& operator|=(const Src rhs); template CheckedNumeric& operator^=(const Src rhs); constexpr CheckedNumeric operator-() const { return CheckedNumeric( NegateWrapper(state_.value()), IsValid() && (!std::is_signed::value || std::is_floating_point::value || NegateWrapper(state_.value()) != std::numeric_limits::lowest())); } constexpr CheckedNumeric operator~() const { return CheckedNumeric( InvertWrapper(state_.value()), IsValid()); } constexpr CheckedNumeric Abs() const { return CheckedNumeric( AbsWrapper(state_.value()), IsValid() && (!std::is_signed::value || std::is_floating_point::value || AbsWrapper(state_.value()) != std::numeric_limits::lowest())); } template constexpr CheckedNumeric::type> Max( const U rhs) const { using R = typename UnderlyingType::type; using result_type = typename MathWrapper::type; // TODO(jschuh): This can be converted to the MathOp version and remain // constexpr once we have C++14 support. return CheckedNumeric( static_cast( IsGreater::Test(state_.value(), Wrapper::value(rhs)) ? state_.value() : Wrapper::value(rhs)), state_.is_valid() && Wrapper::is_valid(rhs)); } template constexpr CheckedNumeric::type> Min( const U rhs) const { using R = typename UnderlyingType::type; using result_type = typename MathWrapper::type; // TODO(jschuh): This can be converted to the MathOp version and remain // constexpr once we have C++14 support. return CheckedNumeric( static_cast( IsLess::Test(state_.value(), Wrapper::value(rhs)) ? state_.value() : Wrapper::value(rhs)), state_.is_valid() && Wrapper::is_valid(rhs)); } // This function is available only for integral types. It returns an unsigned // integer of the same width as the source type, containing the absolute value // of the source, and properly handling signed min. constexpr CheckedNumeric::type> UnsignedAbs() const { return CheckedNumeric::type>( SafeUnsignedAbs(state_.value()), state_.is_valid()); } CheckedNumeric& operator++() { *this += 1; return *this; } CheckedNumeric operator++(int) { CheckedNumeric value = *this; *this += 1; return value; } CheckedNumeric& operator--() { *this -= 1; return *this; } CheckedNumeric operator--(int) { CheckedNumeric value = *this; *this -= 1; return value; } // These perform the actual math operations on the CheckedNumerics. // Binary arithmetic operations. template