Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef CheckedArithmetic_h
     27 #define CheckedArithmetic_h
     28 
     29 #include "wtf/Assertions.h"
     30 #include "wtf/EnumClass.h"
     31 #include "wtf/TypeTraits.h"
     32 
     33 #include <limits>
     34 #include <stdint.h>
     35 
     36 /* Checked<T>
     37  *
     38  * This class provides a mechanism to perform overflow-safe integer arithmetic
     39  * without having to manually ensure that you have all the required bounds checks
     40  * directly in your code.
     41  *
     42  * There are two modes of operation:
     43  *  - The default is Checked<T, CrashOnOverflow>, and crashes at the point
     44  *    and overflow has occurred.
     45  *  - The alternative is Checked<T, RecordOverflow>, which uses an additional
     46  *    byte of storage to track whether an overflow has occurred, subsequent
     47  *    unchecked operations will crash if an overflow has occured
     48  *
     49  * It is possible to provide a custom overflow handler, in which case you need
     50  * to support these functions:
     51  *  - void overflowed();
     52  *    This function is called when an operation has produced an overflow.
     53  *  - bool hasOverflowed();
     54  *    This function must return true if overflowed() has been called on an
     55  *    instance and false if it has not.
     56  *  - void clearOverflow();
     57  *    Used to reset overflow tracking when a value is being overwritten with
     58  *    a new value.
     59  *
     60  * Checked<T> works for all integer types, with the following caveats:
     61  *  - Mixing signedness of operands is only supported for types narrower than
     62  *    64bits.
     63  *  - It does have a performance impact, so tight loops may want to be careful
     64  *    when using it.
     65  *
     66  */
     67 
     68 namespace WTF {
     69 
     70 ENUM_CLASS(CheckedState)
     71 {
     72     DidOverflow,
     73     DidNotOverflow
     74 } ENUM_CLASS_END(CheckedState);
     75 
     76 class CrashOnOverflow {
     77 protected:
     78     NO_RETURN_DUE_TO_CRASH void overflowed()
     79     {
     80         CRASH();
     81     }
     82 
     83     void clearOverflow() { }
     84 
     85 public:
     86     bool hasOverflowed() const { return false; }
     87 };
     88 
     89 class RecordOverflow {
     90 protected:
     91     RecordOverflow()
     92         : m_overflowed(false)
     93     {
     94     }
     95 
     96     void overflowed()
     97     {
     98         m_overflowed = true;
     99     }
    100 
    101     void clearOverflow()
    102     {
    103         m_overflowed = false;
    104     }
    105 
    106 public:
    107     bool hasOverflowed() const { return m_overflowed; }
    108 
    109 private:
    110     unsigned char m_overflowed;
    111 };
    112 
    113 template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
    114 template <typename T> struct RemoveChecked;
    115 template <typename T> struct RemoveChecked<Checked<T> >;
    116 
    117 template <typename Target, typename Source, bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker;
    118 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
    119     static bool inBounds(Source value)
    120     {
    121         // Same signedness so implicit type conversion will always increase precision
    122         // to widest type
    123         return value <= std::numeric_limits<Target>::max();
    124     }
    125 };
    126 
    127 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
    128     static bool inBounds(Source value)
    129     {
    130         // Same signedness so implicit type conversion will always increase precision
    131         // to widest type
    132         return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max();
    133     }
    134 };
    135 
    136 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
    137     static bool inBounds(Source value)
    138     {
    139         // Target is unsigned so any value less than zero is clearly unsafe
    140         if (value < 0)
    141             return false;
    142         // If our (unsigned) Target is the same or greater width we can
    143         // convert value to type Target without losing precision
    144         if (sizeof(Target) >= sizeof(Source))
    145             return static_cast<Target>(value) <= std::numeric_limits<Target>::max();
    146         // The signed Source type has greater precision than the target so
    147         // max(Target) -> Source will widen.
    148         return value <= static_cast<Source>(std::numeric_limits<Target>::max());
    149     }
    150 };
    151 
    152 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
    153     static bool inBounds(Source value)
    154     {
    155         // Signed target with an unsigned source
    156         if (sizeof(Target) <= sizeof(Source))
    157             return value <= static_cast<Source>(std::numeric_limits<Target>::max());
    158         // Target is Wider than Source so we're guaranteed to fit any value in
    159         // unsigned Source
    160         return true;
    161     }
    162 };
    163 
    164 template <typename Target, typename Source, bool CanElide = IsSameType<Target, Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider;
    165 template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
    166     static bool inBounds(Source) { return true; }
    167 };
    168 template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
    169 };
    170 
    171 template <typename Target, typename Source> static inline bool isInBounds(Source value)
    172 {
    173     return BoundsCheckElider<Target, Source>::inBounds(value);
    174 }
    175 
    176 template <typename T> struct RemoveChecked {
    177     typedef T CleanType;
    178     static const CleanType DefaultValue = 0;
    179 };
    180 
    181 template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
    182     typedef typename RemoveChecked<T>::CleanType CleanType;
    183     static const CleanType DefaultValue = 0;
    184 };
    185 
    186 template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
    187     typedef typename RemoveChecked<T>::CleanType CleanType;
    188     static const CleanType DefaultValue = 0;
    189 };
    190 
    191 // The ResultBase and SignednessSelector are used to workaround typeof not being
    192 // available in MSVC
    193 template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
    194 template <typename U, typename V> struct ResultBase<U, V, true, false> {
    195     typedef U ResultType;
    196 };
    197 
    198 template <typename U, typename V> struct ResultBase<U, V, false, false> {
    199     typedef V ResultType;
    200 };
    201 
    202 template <typename U> struct ResultBase<U, U, false, true> {
    203     typedef U ResultType;
    204 };
    205 
    206 template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector;
    207 template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
    208     typedef U ResultType;
    209 };
    210 
    211 template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
    212     typedef U ResultType;
    213 };
    214 
    215 template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
    216     typedef V ResultType;
    217 };
    218 
    219 template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
    220     typedef U ResultType;
    221 };
    222 
    223 template <typename U, typename V> struct ResultBase<U, V, false, true> {
    224     typedef typename SignednessSelector<U, V>::ResultType ResultType;
    225 };
    226 
    227 template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
    228 };
    229 
    230 template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
    231     bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
    232 
    233 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
    234     // LHS and RHS are signed types
    235 
    236     // Helper function
    237     static inline bool signsMatch(LHS lhs, RHS rhs)
    238     {
    239         return (lhs ^ rhs) >= 0;
    240     }
    241 
    242     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    243     {
    244         if (signsMatch(lhs, rhs)) {
    245             if (lhs >= 0) {
    246                 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
    247                     return false;
    248             } else {
    249                 ResultType temp = lhs - std::numeric_limits<ResultType>::min();
    250                 if (rhs < -temp)
    251                     return false;
    252             }
    253         } // if the signs do not match this operation can't overflow
    254         result = lhs + rhs;
    255         return true;
    256     }
    257 
    258     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    259     {
    260         if (!signsMatch(lhs, rhs)) {
    261             if (lhs >= 0) {
    262                 if (lhs > std::numeric_limits<ResultType>::max() + rhs)
    263                     return false;
    264             } else {
    265                 if (rhs > std::numeric_limits<ResultType>::max() + lhs)
    266                     return false;
    267             }
    268         } // if the signs match this operation can't overflow
    269         result = lhs - rhs;
    270         return true;
    271     }
    272 
    273     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    274     {
    275         if (signsMatch(lhs, rhs)) {
    276             if (lhs >= 0) {
    277                 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
    278                     return false;
    279             } else {
    280                 if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultType>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::min())
    281                     return false;
    282                 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
    283                     return false;
    284             }
    285         } else {
    286             if (lhs < 0) {
    287                 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
    288                     return false;
    289             } else {
    290                 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
    291                     return false;
    292             }
    293         }
    294         result = lhs * rhs;
    295         return true;
    296     }
    297 
    298     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
    299 
    300 };
    301 
    302 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
    303     // LHS and RHS are unsigned types so bounds checks are nice and easy
    304     static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    305     {
    306         ResultType temp = lhs + rhs;
    307         if (temp < lhs)
    308             return false;
    309         result = temp;
    310         return true;
    311     }
    312 
    313     static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    314     {
    315         ResultType temp = lhs - rhs;
    316         if (temp > lhs)
    317             return false;
    318         result = temp;
    319         return true;
    320     }
    321 
    322     static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
    323     {
    324         if (!lhs || !rhs) {
    325             result = 0;
    326             return true;
    327         }
    328         if (std::numeric_limits<ResultType>::max() / lhs < rhs)
    329             return false;
    330         result = lhs * rhs;
    331         return true;
    332     }
    333 
    334     static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
    335 
    336 };
    337 
    338 template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
    339     static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
    340     {
    341         int64_t temp = lhs + rhs;
    342         if (temp < std::numeric_limits<ResultType>::min())
    343             return false;
    344         if (temp > std::numeric_limits<ResultType>::max())
    345             return false;
    346         result = static_cast<ResultType>(temp);
    347         return true;
    348     }
    349 
    350     static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
    351     {
    352         int64_t temp = lhs - rhs;
    353         if (temp < std::numeric_limits<ResultType>::min())
    354             return false;
    355         if (temp > std::numeric_limits<ResultType>::max())
    356             return false;
    357         result = static_cast<ResultType>(temp);
    358         return true;
    359     }
    360 
    361     static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
    362     {
    363         int64_t temp = lhs * rhs;
    364         if (temp < std::numeric_limits<ResultType>::min())
    365             return false;
    366         if (temp > std::numeric_limits<ResultType>::max())
    367             return false;
    368         result = static_cast<ResultType>(temp);
    369         return true;
    370     }
    371 
    372     static inline bool equals(int lhs, unsigned rhs)
    373     {
    374         return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
    375     }
    376 };
    377 
    378 template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
    379     static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
    380     {
    381         return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
    382     }
    383 
    384     static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
    385     {
    386         return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
    387     }
    388 
    389     static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
    390     {
    391         return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
    392     }
    393 
    394     static inline bool equals(unsigned lhs, int rhs)
    395     {
    396         return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
    397     }
    398 };
    399 
    400 template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
    401 {
    402     return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
    403 }
    404 
    405 template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
    406 {
    407     return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
    408 }
    409 
    410 template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
    411 {
    412     return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
    413 }
    414 
    415 template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
    416 {
    417     return ArithmeticOperations<U, V>::equals(lhs, rhs);
    418 }
    419 
    420 enum ResultOverflowedTag { ResultOverflowed };
    421 
    422 template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
    423 public:
    424     template <typename _T, class _OverflowHandler> friend class Checked;
    425     Checked()
    426         : m_value(0)
    427     {
    428     }
    429 
    430     Checked(ResultOverflowedTag)
    431         : m_value(0)
    432     {
    433         this->overflowed();
    434     }
    435 
    436     template <typename U> Checked(U value)
    437     {
    438         if (!isInBounds<T>(value))
    439             this->overflowed();
    440         m_value = static_cast<T>(value);
    441     }
    442 
    443     template <typename V> Checked(const Checked<T, V>& rhs)
    444         : m_value(rhs.m_value)
    445     {
    446         if (rhs.hasOverflowed())
    447             this->overflowed();
    448     }
    449 
    450     template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
    451         : OverflowHandler(rhs)
    452     {
    453         if (!isInBounds<T>(rhs.m_value))
    454             this->overflowed();
    455         m_value = static_cast<T>(rhs.m_value);
    456     }
    457 
    458     template <typename U, typename V> Checked(const Checked<U, V>& rhs)
    459     {
    460         if (rhs.hasOverflowed())
    461             this->overflowed();
    462         if (!isInBounds<T>(rhs.m_value))
    463             this->overflowed();
    464         m_value = static_cast<T>(rhs.m_value);
    465     }
    466 
    467     const Checked& operator=(Checked rhs)
    468     {
    469         this->clearOverflow();
    470         if (rhs.hasOverflowed())
    471             this->overflowed();
    472         m_value = static_cast<T>(rhs.m_value);
    473         return *this;
    474     }
    475 
    476     template <typename U> const Checked& operator=(U value)
    477     {
    478         return *this = Checked(value);
    479     }
    480 
    481     template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
    482     {
    483         return *this = Checked(rhs);
    484     }
    485 
    486     // prefix
    487     const Checked& operator++()
    488     {
    489         if (m_value == std::numeric_limits<T>::max())
    490             this->overflowed();
    491         m_value++;
    492         return *this;
    493     }
    494 
    495     const Checked& operator--()
    496     {
    497         if (m_value == std::numeric_limits<T>::min())
    498             this->overflowed();
    499         m_value--;
    500         return *this;
    501     }
    502 
    503     // postfix operators
    504     const Checked operator++(int)
    505     {
    506         if (m_value == std::numeric_limits<T>::max())
    507             this->overflowed();
    508         return Checked(m_value++);
    509     }
    510 
    511     const Checked operator--(int)
    512     {
    513         if (m_value == std::numeric_limits<T>::min())
    514             this->overflowed();
    515         return Checked(m_value--);
    516     }
    517 
    518     // Boolean operators
    519     bool operator!() const
    520     {
    521         if (this->hasOverflowed())
    522             CRASH();
    523         return !m_value;
    524     }
    525 
    526     typedef void* (Checked::*UnspecifiedBoolType);
    527     operator UnspecifiedBoolType*() const
    528     {
    529         if (this->hasOverflowed())
    530             CRASH();
    531         return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
    532     }
    533 
    534     // Value accessors. unsafeGet() will crash if there's been an overflow.
    535     T unsafeGet() const
    536     {
    537         if (this->hasOverflowed())
    538             CRASH();
    539         return m_value;
    540     }
    541 
    542     inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
    543     {
    544         value = m_value;
    545         if (this->hasOverflowed())
    546             return CheckedState::DidOverflow;
    547         return CheckedState::DidNotOverflow;
    548     }
    549 
    550     // Mutating assignment
    551     template <typename U> const Checked operator+=(U rhs)
    552     {
    553         if (!safeAdd(m_value, rhs, m_value))
    554             this->overflowed();
    555         return *this;
    556     }
    557 
    558     template <typename U> const Checked operator-=(U rhs)
    559     {
    560         if (!safeSub(m_value, rhs, m_value))
    561             this->overflowed();
    562         return *this;
    563     }
    564 
    565     template <typename U> const Checked operator*=(U rhs)
    566     {
    567         if (!safeMultiply(m_value, rhs, m_value))
    568             this->overflowed();
    569         return *this;
    570     }
    571 
    572     const Checked operator*=(double rhs)
    573     {
    574         double result = rhs * m_value;
    575         // Handle +/- infinity and NaN
    576         if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
    577             this->overflowed();
    578         m_value = (T)result;
    579         return *this;
    580     }
    581 
    582     const Checked operator*=(float rhs)
    583     {
    584         return *this *= (double)rhs;
    585     }
    586 
    587     template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
    588     {
    589         if (rhs.hasOverflowed())
    590             this->overflowed();
    591         return *this += rhs.m_value;
    592     }
    593 
    594     template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
    595     {
    596         if (rhs.hasOverflowed())
    597             this->overflowed();
    598         return *this -= rhs.m_value;
    599     }
    600 
    601     template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
    602     {
    603         if (rhs.hasOverflowed())
    604             this->overflowed();
    605         return *this *= rhs.m_value;
    606     }
    607 
    608     // Equality comparisons
    609     template <typename V> bool operator==(Checked<T, V> rhs)
    610     {
    611         return unsafeGet() == rhs.unsafeGet();
    612     }
    613 
    614     template <typename U> bool operator==(U rhs)
    615     {
    616         if (this->hasOverflowed())
    617             this->overflowed();
    618         return safeEquals(m_value, rhs);
    619     }
    620 
    621     template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
    622     {
    623         return unsafeGet() == Checked(rhs.unsafeGet());
    624     }
    625 
    626     template <typename U> bool operator!=(U rhs)
    627     {
    628         return !(*this == rhs);
    629     }
    630 
    631 private:
    632     // Disallow implicit conversion of floating point to integer types
    633     Checked(float);
    634     Checked(double);
    635     void operator=(float);
    636     void operator=(double);
    637     void operator+=(float);
    638     void operator+=(double);
    639     void operator-=(float);
    640     void operator-=(double);
    641     T m_value;
    642 };
    643 
    644 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
    645 {
    646     U x = 0;
    647     V y = 0;
    648     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    649     typename Result<U, V>::ResultType result = 0;
    650     overflowed |= !safeAdd(x, y, result);
    651     if (overflowed)
    652         return ResultOverflowed;
    653     return result;
    654 }
    655 
    656 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
    657 {
    658     U x = 0;
    659     V y = 0;
    660     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    661     typename Result<U, V>::ResultType result = 0;
    662     overflowed |= !safeSub(x, y, result);
    663     if (overflowed)
    664         return ResultOverflowed;
    665     return result;
    666 }
    667 
    668 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
    669 {
    670     U x = 0;
    671     V y = 0;
    672     bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
    673     typename Result<U, V>::ResultType result = 0;
    674     overflowed |= !safeMultiply(x, y, result);
    675     if (overflowed)
    676         return ResultOverflowed;
    677     return result;
    678 }
    679 
    680 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
    681 {
    682     return lhs + Checked<V, OverflowHandler>(rhs);
    683 }
    684 
    685 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
    686 {
    687     return lhs - Checked<V, OverflowHandler>(rhs);
    688 }
    689 
    690 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
    691 {
    692     return lhs * Checked<V, OverflowHandler>(rhs);
    693 }
    694 
    695 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
    696 {
    697     return Checked<U, OverflowHandler>(lhs) + rhs;
    698 }
    699 
    700 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
    701 {
    702     return Checked<U, OverflowHandler>(lhs) - rhs;
    703 }
    704 
    705 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
    706 {
    707     return Checked<U, OverflowHandler>(lhs) * rhs;
    708 }
    709 
    710 }
    711 
    712 using WTF::Checked;
    713 using WTF::CheckedState;
    714 using WTF::RecordOverflow;
    715 
    716 #endif
    717