LCOV - code coverage report
Current view: top level - src/base - safe_math.h (source / functions) Hit Total Coverage
Test: app.info Lines: 10 10 100.0 %
Date: 2019-01-20 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright 2014 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             : // Slightly adapted for inclusion in V8.
       6             : // Copyright 2014 the V8 project authors. All rights reserved.
       7             : 
       8             : #ifndef V8_BASE_SAFE_MATH_H_
       9             : #define V8_BASE_SAFE_MATH_H_
      10             : 
      11             : #include "src/base/safe_math_impl.h"
      12             : 
      13             : namespace v8 {
      14             : namespace base {
      15             : namespace internal {
      16             : 
      17             : // CheckedNumeric implements all the logic and operators for detecting integer
      18             : // boundary conditions such as overflow, underflow, and invalid conversions.
      19             : // The CheckedNumeric type implicitly converts from floating point and integer
      20             : // data types, and contains overloads for basic arithmetic operations (i.e.: +,
      21             : // -, *, /, %).
      22             : //
      23             : // The following methods convert from CheckedNumeric to standard numeric values:
      24             : // IsValid() - Returns true if the underlying numeric value is valid (i.e. has
      25             : //             has not wrapped and is not the result of an invalid conversion).
      26             : // ValueOrDie() - Returns the underlying value. If the state is not valid this
      27             : //                call will crash on a CHECK.
      28             : // ValueOrDefault() - Returns the current value, or the supplied default if the
      29             : //                    state is not valid.
      30             : // ValueFloating() - Returns the underlying floating point value (valid only
      31             : //                   only for floating point CheckedNumeric types).
      32             : //
      33             : // Bitwise operations are explicitly not supported, because correct
      34             : // handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
      35             : // operations are explicitly not supported because they could result in a crash
      36             : // on a CHECK condition. You should use patterns like the following for these
      37             : // operations:
      38             : // Bitwise operation:
      39             : //     CheckedNumeric<int> checked_int = untrusted_input_value;
      40             : //     int x = checked_int.ValueOrDefault(0) | kFlagValues;
      41             : // Comparison:
      42             : //   CheckedNumeric<size_t> checked_size;
      43             : //   CheckedNumeric<int> checked_size = untrusted_input_value;
      44             : //   checked_size = checked_size + HEADER LENGTH;
      45             : //   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
      46             : //     Do stuff...
      47             : template <typename T>
      48             : class CheckedNumeric {
      49             :  public:
      50             :   typedef T type;
      51             : 
      52             :   CheckedNumeric() = default;
      53             : 
      54             :   // Copy constructor.
      55             :   template <typename Src>
      56             :   CheckedNumeric(const CheckedNumeric<Src>& rhs)
      57             :       : state_(rhs.ValueUnsafe(), rhs.validity()) {}
      58             : 
      59             :   template <typename Src>
      60             :   CheckedNumeric(Src value, RangeConstraint validity)
      61             :       : state_(value, validity) {}
      62             : 
      63             :   // This is not an explicit constructor because we implicitly upgrade regular
      64             :   // numerics to CheckedNumerics to make them easier to use.
      65             :   template <typename Src>
      66    43506357 :   CheckedNumeric(Src value)  // NOLINT
      67             :       : state_(value) {
      68             :     // Argument must be numeric.
      69             :     STATIC_ASSERT(std::numeric_limits<Src>::is_specialized);
      70    43506357 :   }
      71             : 
      72             :   // IsValid() is the public API to test if a CheckedNumeric is currently valid.
      73             :   bool IsValid() const { return validity() == RANGE_VALID; }
      74             : 
      75             :   // ValueOrDie() The primary accessor for the underlying value. If the current
      76             :   // state is not valid it will CHECK and crash.
      77    43505230 :   T ValueOrDie() const {
      78    43505230 :     CHECK(IsValid());
      79    43505230 :     return state_.value();
      80             :   }
      81             : 
      82             :   // ValueOrDefault(T default_value) A convenience method that returns the
      83             :   // current value if the state is valid, and the supplied default_value for
      84             :   // any other state.
      85             :   T ValueOrDefault(T default_value) const {
      86      114412 :     return IsValid() ? state_.value() : default_value;
      87             :   }
      88             : 
      89             :   // ValueFloating() - Since floating point values include their validity state,
      90             :   // we provide an easy method for extracting them directly, without a risk of
      91             :   // crashing on a CHECK.
      92             :   T ValueFloating() const {
      93             :     // Argument must be a floating-point value.
      94             :     STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
      95             :     return CheckedNumeric<T>::cast(*this).ValueUnsafe();
      96             :   }
      97             : 
      98             :   // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
      99             :   // tests and to avoid a big matrix of friend operator overloads. But the
     100             :   // values it returns are likely to change in the future.
     101             :   // Returns: current validity state (i.e. valid, overflow, underflow, nan).
     102             :   // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
     103             :   // saturation/wrapping so we can expose this state consistently and implement
     104             :   // saturated arithmetic.
     105   174025555 :   RangeConstraint validity() const { return state_.validity(); }
     106             : 
     107             :   // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
     108             :   // for tests and to avoid a big matrix of friend operator overloads. But the
     109             :   // values it returns are likely to change in the future.
     110             :   // Returns: the raw numeric value, regardless of the current state.
     111             :   // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
     112             :   // saturation/wrapping so we can expose this state consistently and implement
     113             :   // saturated arithmetic.
     114    87013193 :   T ValueUnsafe() const { return state_.value(); }
     115             : 
     116             :   // Prototypes for the supported arithmetic operator overloads.
     117             :   template <typename Src> CheckedNumeric& operator+=(Src rhs);
     118             :   template <typename Src> CheckedNumeric& operator-=(Src rhs);
     119             :   template <typename Src> CheckedNumeric& operator*=(Src rhs);
     120             :   template <typename Src> CheckedNumeric& operator/=(Src rhs);
     121             :   template <typename Src> CheckedNumeric& operator%=(Src rhs);
     122             : 
     123             :   CheckedNumeric operator-() const {
     124             :     RangeConstraint validity;
     125             :     T value = CheckedNeg(state_.value(), &validity);
     126             :     // Negation is always valid for floating point.
     127             :     if (std::numeric_limits<T>::is_iec559)
     128             :       return CheckedNumeric<T>(value);
     129             : 
     130             :     validity = GetRangeConstraint(state_.validity() | validity);
     131             :     return CheckedNumeric<T>(value, validity);
     132             :   }
     133             : 
     134             :   CheckedNumeric Abs() const {
     135             :     RangeConstraint validity;
     136             :     T value = CheckedAbs(state_.value(), &validity);
     137             :     // Absolute value is always valid for floating point.
     138             :     if (std::numeric_limits<T>::is_iec559)
     139             :       return CheckedNumeric<T>(value);
     140             : 
     141             :     validity = GetRangeConstraint(state_.validity() | validity);
     142             :     return CheckedNumeric<T>(value, validity);
     143             :   }
     144             : 
     145             :   CheckedNumeric& operator++() {
     146             :     *this += 1;
     147             :     return *this;
     148             :   }
     149             : 
     150             :   CheckedNumeric operator++(int) {
     151             :     CheckedNumeric value = *this;
     152             :     *this += 1;
     153             :     return value;
     154             :   }
     155             : 
     156             :   CheckedNumeric& operator--() {
     157             :     *this -= 1;
     158             :     return *this;
     159             :   }
     160             : 
     161             :   CheckedNumeric operator--(int) {
     162             :     CheckedNumeric value = *this;
     163             :     *this -= 1;
     164             :     return value;
     165             :   }
     166             : 
     167             :   // These static methods behave like a convenience cast operator targeting
     168             :   // the desired CheckedNumeric type. As an optimization, a reference is
     169             :   // returned when Src is the same type as T.
     170             :   template <typename Src>
     171             :   static CheckedNumeric<T> cast(
     172             :       Src u,
     173             :       typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
     174             :           0) {
     175             :     return u;
     176             :   }
     177             : 
     178             :   template <typename Src>
     179             :   static CheckedNumeric<T> cast(
     180             :       const CheckedNumeric<Src>& u,
     181             :       typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
     182             :     return u;
     183             :   }
     184             : 
     185             :   static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
     186             : 
     187             :  private:
     188             :   CheckedNumericState<T> state_;
     189             : };
     190             : 
     191             : // This is the boilerplate for the standard arithmetic operator overloads. A
     192             : // macro isn't the prettiest solution, but it beats rewriting these five times.
     193             : // Some details worth noting are:
     194             : //  * We apply the standard arithmetic promotions.
     195             : //  * We skip range checks for floating points.
     196             : //  * We skip range checks for destination integers with sufficient range.
     197             : // TODO(jschuh): extract these out into templates.
     198             : #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)              \
     199             :   /* Binary arithmetic operator for CheckedNumerics of the same type. */      \
     200             :   template <typename T>                                                       \
     201             :   CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP(          \
     202             :       const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) {           \
     203             :     typedef typename ArithmeticPromotion<T>::type Promotion;                  \
     204             :     /* Floating point always takes the fast path */                           \
     205             :     if (std::numeric_limits<T>::is_iec559)                                    \
     206             :       return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());       \
     207             :     if (IsIntegerArithmeticSafe<Promotion, T, T>::value)                      \
     208             :       return CheckedNumeric<Promotion>(                                       \
     209             :           lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
     210             :           GetRangeConstraint(rhs.validity() | lhs.validity()));               \
     211             :     RangeConstraint validity = RANGE_VALID;                                   \
     212             :     T result = Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()),       \
     213             :                              static_cast<Promotion>(rhs.ValueUnsafe()),       \
     214             :                              &validity);                                      \
     215             :     return CheckedNumeric<Promotion>(                                         \
     216             :         result,                                                               \
     217             :         GetRangeConstraint(validity | lhs.validity() | rhs.validity()));      \
     218             :   }                                                                           \
     219             :   /* Assignment arithmetic operator implementation from CheckedNumeric. */    \
     220             :   template <typename T>                                                       \
     221             :   template <typename Src>                                                     \
     222             :   CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) {       \
     223             :     *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
     224             :     return *this;                                                             \
     225             :   }                                                                           \
     226             :   /* Binary arithmetic operator for CheckedNumeric of different type. */      \
     227             :   template <typename T, typename Src>                                         \
     228             :   CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
     229             :       const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) {         \
     230             :     typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
     231             :     if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
     232             :       return CheckedNumeric<Promotion>(                                       \
     233             :           lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
     234             :           GetRangeConstraint(rhs.validity() | lhs.validity()));               \
     235             :     return CheckedNumeric<Promotion>::cast(lhs)                               \
     236             :         OP CheckedNumeric<Promotion>::cast(rhs);                              \
     237             :   }                                                                           \
     238             :   /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
     239             :   template <typename T, typename Src>                                         \
     240             :   CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
     241             :       const CheckedNumeric<T>& lhs, Src rhs) {                                \
     242             :     typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
     243             :     if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
     244             :       return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs,              \
     245             :                                        lhs.validity());                       \
     246             :     return CheckedNumeric<Promotion>::cast(lhs)                               \
     247             :         OP CheckedNumeric<Promotion>::cast(rhs);                              \
     248             :   }                                                                           \
     249             :   /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
     250             :   template <typename T, typename Src>                                         \
     251             :   CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
     252             :       Src lhs, const CheckedNumeric<T>& rhs) {                                \
     253             :     typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
     254             :     if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
     255             :       return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(),              \
     256             :                                        rhs.validity());                       \
     257             :     return CheckedNumeric<Promotion>::cast(lhs)                               \
     258             :         OP CheckedNumeric<Promotion>::cast(rhs);                              \
     259             :   }
     260             : 
     261   130517949 : BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
     262             : BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
     263   261043337 : BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
     264             : BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
     265             : BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
     266             : 
     267             : #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
     268             : 
     269             : }  // namespace internal
     270             : 
     271             : using internal::CheckedNumeric;
     272             : 
     273             : }  // namespace base
     274             : }  // namespace v8
     275             : 
     276             : #endif  // V8_BASE_SAFE_MATH_H_

Generated by: LCOV version 1.10