1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/yarr/CheckedArithmetic.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,715 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * 1.7 + * Copyright (C) 2011 Apple Inc. All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions 1.11 + * are met: 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 2. Redistributions in binary form must reproduce the above copyright 1.15 + * notice, this list of conditions and the following disclaimer in the 1.16 + * documentation and/or other materials provided with the distribution. 1.17 + * 1.18 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 1.19 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1.21 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 1.22 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1.23 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1.24 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 1.25 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 1.26 + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.27 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.28 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.29 + */ 1.30 + 1.31 +#ifndef yarr_CheckedArithmetic_h 1.32 +#define yarr_CheckedArithmetic_h 1.33 + 1.34 +#include "assembler/wtf/Assertions.h" 1.35 + 1.36 +#include <limits> 1.37 +#include <stdint.h> 1.38 +#include "mozilla/TypeTraits.h" 1.39 + 1.40 +#ifdef _MSC_VER 1.41 +# undef min 1.42 +# undef max 1.43 +#endif 1.44 + 1.45 +/* Checked<T> 1.46 + * 1.47 + * This class provides a mechanism to perform overflow-safe integer arithmetic 1.48 + * without having to manually ensure that you have all the required bounds checks 1.49 + * directly in your code. 1.50 + * 1.51 + * There are two modes of operation: 1.52 + * - The default is Checked<T, CrashOnOverflow>, and crashes at the point 1.53 + * and overflow has occurred. 1.54 + * - The alternative is Checked<T, RecordOverflow>, which uses an additional 1.55 + * byte of storage to track whether an overflow has occurred, subsequent 1.56 + * unchecked operations will crash if an overflow has occured 1.57 + * 1.58 + * It is possible to provide a custom overflow handler, in which case you need 1.59 + * to support these functions: 1.60 + * - void overflowed(); 1.61 + * This function is called when an operation has produced an overflow. 1.62 + * - bool hasOverflowed(); 1.63 + * This function must return true if overflowed() has been called on an 1.64 + * instance and false if it has not. 1.65 + * - void clearOverflow(); 1.66 + * Used to reset overflow tracking when a value is being overwritten with 1.67 + * a new value. 1.68 + * 1.69 + * Checked<T> works for all integer types, with the following caveats: 1.70 + * - Mixing signedness of operands is only supported for types narrower than 1.71 + * 64bits. 1.72 + * - It does have a performance impact, so tight loops may want to be careful 1.73 + * when using it. 1.74 + * 1.75 + */ 1.76 + 1.77 +namespace WTF { 1.78 + 1.79 +class CrashOnOverflow { 1.80 +protected: 1.81 + void overflowed() 1.82 + { 1.83 + CRASH(); 1.84 + } 1.85 + 1.86 + void clearOverflow() { } 1.87 + 1.88 +public: 1.89 + bool hasOverflowed() const { return false; } 1.90 +}; 1.91 + 1.92 +class RecordOverflow { 1.93 +protected: 1.94 + RecordOverflow() 1.95 + : m_overflowed(false) 1.96 + { 1.97 + } 1.98 + 1.99 + void overflowed() 1.100 + { 1.101 + m_overflowed = true; 1.102 + } 1.103 + 1.104 + void clearOverflow() 1.105 + { 1.106 + m_overflowed = false; 1.107 + } 1.108 + 1.109 +public: 1.110 + bool hasOverflowed() const { return m_overflowed; } 1.111 + 1.112 +private: 1.113 + unsigned char m_overflowed; 1.114 +}; 1.115 + 1.116 +template <typename T, class OverflowHandler = RecordOverflow> class Checked; 1.117 +template <typename T> struct RemoveChecked; 1.118 +template <typename T> struct RemoveChecked<Checked<T> >; 1.119 + 1.120 +template <typename Target, typename Source, bool targetSigned = ::std::numeric_limits<Target>::is_signed, bool sourceSigned = ::std::numeric_limits<Source>::is_signed> struct BoundsChecker; 1.121 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> { 1.122 + static bool inBounds(Source value) 1.123 + { 1.124 + // Same signedness so implicit type conversion will always increase precision 1.125 + // to widest type 1.126 + return value <= ::std::numeric_limits<Target>::max(); 1.127 + } 1.128 +}; 1.129 + 1.130 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> { 1.131 + static bool inBounds(Source value) 1.132 + { 1.133 + // Same signedness so implicit type conversion will always increase precision 1.134 + // to widest type 1.135 + return ::std::numeric_limits<Target>::min() <= value && value <= ::std::numeric_limits<Target>::max(); 1.136 + } 1.137 +}; 1.138 + 1.139 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> { 1.140 + static bool inBounds(Source value) 1.141 + { 1.142 + // Target is unsigned so any value less than zero is clearly unsafe 1.143 + if (value < 0) 1.144 + return false; 1.145 + // If our (unsigned) Target is the same or greater width we can 1.146 + // convert value to type Target without losing precision 1.147 + if (sizeof(Target) >= sizeof(Source)) 1.148 + return static_cast<Target>(value) <= ::std::numeric_limits<Target>::max(); 1.149 + // The signed Source type has greater precision than the target so 1.150 + // max(Target) -> Source will widen. 1.151 + return value <= static_cast<Source>(::std::numeric_limits<Target>::max()); 1.152 + } 1.153 +}; 1.154 + 1.155 +template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> { 1.156 + static bool inBounds(Source value) 1.157 + { 1.158 + // Signed target with an unsigned source 1.159 + if (sizeof(Target) <= sizeof(Source)) 1.160 + return value <= static_cast<Source>(::std::numeric_limits<Target>::max()); 1.161 + // Target is Wider than Source so we're guaranteed to fit any value in 1.162 + // unsigned Source 1.163 + return true; 1.164 + } 1.165 +}; 1.166 + 1.167 +template <typename Target, typename Source, bool SameType = mozilla::IsSame<Target, Source>::value> struct BoundsCheckElider; 1.168 +template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> { 1.169 + static bool inBounds(Source) { return true; } 1.170 +}; 1.171 +template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> { 1.172 +}; 1.173 + 1.174 +template <typename Target, typename Source> static inline bool isInBounds(Source value) 1.175 +{ 1.176 + return BoundsCheckElider<Target, Source>::inBounds(value); 1.177 +} 1.178 + 1.179 +template <typename T> struct RemoveChecked { 1.180 + typedef T CleanType; 1.181 + static const CleanType DefaultValue = 0; 1.182 +}; 1.183 + 1.184 +template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > { 1.185 + typedef typename RemoveChecked<T>::CleanType CleanType; 1.186 + static const CleanType DefaultValue = 0; 1.187 +}; 1.188 + 1.189 +template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > { 1.190 + typedef typename RemoveChecked<T>::CleanType CleanType; 1.191 + static const CleanType DefaultValue = 0; 1.192 +}; 1.193 + 1.194 +// The ResultBase and SignednessSelector are used to workaround typeof not being 1.195 +// available in MSVC 1.196 +template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; 1.197 +template <typename U, typename V> struct ResultBase<U, V, true, false> { 1.198 + typedef U ResultType; 1.199 +}; 1.200 + 1.201 +template <typename U, typename V> struct ResultBase<U, V, false, false> { 1.202 + typedef V ResultType; 1.203 +}; 1.204 + 1.205 +template <typename U> struct ResultBase<U, U, false, true> { 1.206 + typedef U ResultType; 1.207 +}; 1.208 + 1.209 +template <typename U, typename V, bool uIsSigned = ::std::numeric_limits<U>::is_signed, bool vIsSigned = ::std::numeric_limits<V>::is_signed> struct SignednessSelector; 1.210 +template <typename U, typename V> struct SignednessSelector<U, V, true, true> { 1.211 + typedef U ResultType; 1.212 +}; 1.213 + 1.214 +template <typename U, typename V> struct SignednessSelector<U, V, false, false> { 1.215 + typedef U ResultType; 1.216 +}; 1.217 + 1.218 +template <typename U, typename V> struct SignednessSelector<U, V, true, false> { 1.219 + typedef V ResultType; 1.220 +}; 1.221 + 1.222 +template <typename U, typename V> struct SignednessSelector<U, V, false, true> { 1.223 + typedef U ResultType; 1.224 +}; 1.225 + 1.226 +template <typename U, typename V> struct ResultBase<U, V, false, true> { 1.227 + typedef typename SignednessSelector<U, V>::ResultType ResultType; 1.228 +}; 1.229 + 1.230 +template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> { 1.231 +}; 1.232 + 1.233 +template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType, 1.234 + bool lhsSigned = ::std::numeric_limits<LHS>::is_signed, bool rhsSigned = ::std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations; 1.235 + 1.236 +template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> { 1.237 + // LHS and RHS are signed types 1.238 + 1.239 + // Helper function 1.240 + static inline bool signsMatch(LHS lhs, RHS rhs) 1.241 + { 1.242 + return (lhs ^ rhs) >= 0; 1.243 + } 1.244 + 1.245 + static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.246 + { 1.247 + if (signsMatch(lhs, rhs)) { 1.248 + if (lhs >= 0) { 1.249 + if ((::std::numeric_limits<ResultType>::max() - rhs) < lhs) 1.250 + return false; 1.251 + } else { 1.252 + ResultType temp = lhs - ::std::numeric_limits<ResultType>::min(); 1.253 + if (rhs < -temp) 1.254 + return false; 1.255 + } 1.256 + } // if the signs do not match this operation can't overflow 1.257 + result = lhs + rhs; 1.258 + return true; 1.259 + } 1.260 + 1.261 + static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.262 + { 1.263 + if (!signsMatch(lhs, rhs)) { 1.264 + if (lhs >= 0) { 1.265 + if (lhs > ::std::numeric_limits<ResultType>::max() + rhs) 1.266 + return false; 1.267 + } else { 1.268 + if (rhs > ::std::numeric_limits<ResultType>::max() + lhs) 1.269 + return false; 1.270 + } 1.271 + } // if the signs match this operation can't overflow 1.272 + result = lhs - rhs; 1.273 + return true; 1.274 + } 1.275 + 1.276 + static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.277 + { 1.278 + if (signsMatch(lhs, rhs)) { 1.279 + if (lhs >= 0) { 1.280 + if (lhs && (::std::numeric_limits<ResultType>::max() / lhs) < rhs) 1.281 + return false; 1.282 + } else { 1.283 + if (lhs == ::std::numeric_limits<ResultType>::min() || rhs == ::std::numeric_limits<ResultType>::min()) 1.284 + return false; 1.285 + if ((::std::numeric_limits<ResultType>::max() / -lhs) < -rhs) 1.286 + return false; 1.287 + } 1.288 + } else { 1.289 + if (lhs < 0) { 1.290 + if (rhs && lhs < (::std::numeric_limits<ResultType>::min() / rhs)) 1.291 + return false; 1.292 + } else { 1.293 + if (lhs && rhs < (::std::numeric_limits<ResultType>::min() / lhs)) 1.294 + return false; 1.295 + } 1.296 + } 1.297 + result = lhs * rhs; 1.298 + return true; 1.299 + } 1.300 + 1.301 + static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } 1.302 + 1.303 +}; 1.304 + 1.305 +template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> { 1.306 + // LHS and RHS are unsigned types so bounds checks are nice and easy 1.307 + static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.308 + { 1.309 + ResultType temp = lhs + rhs; 1.310 + if (temp < lhs) 1.311 + return false; 1.312 + result = temp; 1.313 + return true; 1.314 + } 1.315 + 1.316 + static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.317 + { 1.318 + ResultType temp = lhs - rhs; 1.319 + if (temp > lhs) 1.320 + return false; 1.321 + result = temp; 1.322 + return true; 1.323 + } 1.324 + 1.325 + static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN 1.326 + { 1.327 + ResultType temp = lhs * rhs; 1.328 + if (temp < lhs) 1.329 + return false; 1.330 + result = temp; 1.331 + return true; 1.332 + } 1.333 + 1.334 + static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } 1.335 + 1.336 +}; 1.337 + 1.338 +template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> { 1.339 + static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) 1.340 + { 1.341 + int64_t temp = lhs + rhs; 1.342 + if (temp < ::std::numeric_limits<ResultType>::min()) 1.343 + return false; 1.344 + if (temp > ::std::numeric_limits<ResultType>::max()) 1.345 + return false; 1.346 + result = static_cast<ResultType>(temp); 1.347 + return true; 1.348 + } 1.349 + 1.350 + static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) 1.351 + { 1.352 + int64_t temp = lhs - rhs; 1.353 + if (temp < ::std::numeric_limits<ResultType>::min()) 1.354 + return false; 1.355 + if (temp > ::std::numeric_limits<ResultType>::max()) 1.356 + return false; 1.357 + result = static_cast<ResultType>(temp); 1.358 + return true; 1.359 + } 1.360 + 1.361 + static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) 1.362 + { 1.363 + int64_t temp = lhs * rhs; 1.364 + if (temp < ::std::numeric_limits<ResultType>::min()) 1.365 + return false; 1.366 + if (temp > ::std::numeric_limits<ResultType>::max()) 1.367 + return false; 1.368 + result = static_cast<ResultType>(temp); 1.369 + return true; 1.370 + } 1.371 + 1.372 + static inline bool equals(int lhs, unsigned rhs) 1.373 + { 1.374 + return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs); 1.375 + } 1.376 +}; 1.377 + 1.378 +template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> { 1.379 + static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) 1.380 + { 1.381 + return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result); 1.382 + } 1.383 + 1.384 + static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) 1.385 + { 1.386 + return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result); 1.387 + } 1.388 + 1.389 + static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) 1.390 + { 1.391 + return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result); 1.392 + } 1.393 + 1.394 + static inline bool equals(unsigned lhs, int rhs) 1.395 + { 1.396 + return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs); 1.397 + } 1.398 +}; 1.399 + 1.400 +template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result) 1.401 +{ 1.402 + return ArithmeticOperations<U, V, R>::add(lhs, rhs, result); 1.403 +} 1.404 + 1.405 +template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result) 1.406 +{ 1.407 + return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result); 1.408 +} 1.409 + 1.410 +template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result) 1.411 +{ 1.412 + return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result); 1.413 +} 1.414 + 1.415 +template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs) 1.416 +{ 1.417 + return ArithmeticOperations<U, V>::equals(lhs, rhs); 1.418 +} 1.419 + 1.420 +enum ResultOverflowedTag { ResultOverflowed }; 1.421 + 1.422 +// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801 1.423 +static inline bool workAroundClangBug() { return true; } 1.424 + 1.425 +template <typename T, class OverflowHandler> class Checked : public OverflowHandler { 1.426 +public: 1.427 + template <typename _T, class _OverflowHandler> friend class Checked; 1.428 + Checked() 1.429 + : m_value(0) 1.430 + { 1.431 + } 1.432 + 1.433 + Checked(ResultOverflowedTag) 1.434 + : m_value(0) 1.435 + { 1.436 + // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801 1.437 + if (workAroundClangBug()) 1.438 + this->overflowed(); 1.439 + } 1.440 + 1.441 + template <typename U> Checked(U value) 1.442 + { 1.443 + if (!isInBounds<T>(value)) 1.444 + this->overflowed(); 1.445 + m_value = static_cast<T>(value); 1.446 + } 1.447 + 1.448 + template <typename V> Checked(const Checked<T, V>& rhs) 1.449 + : m_value(rhs.m_value) 1.450 + { 1.451 + if (rhs.hasOverflowed()) 1.452 + this->overflowed(); 1.453 + } 1.454 + 1.455 + template <typename U> Checked(const Checked<U, OverflowHandler>& rhs) 1.456 + : OverflowHandler(rhs) 1.457 + { 1.458 + if (!isInBounds<T>(rhs.m_value)) 1.459 + this->overflowed(); 1.460 + m_value = static_cast<T>(rhs.m_value); 1.461 + } 1.462 + 1.463 + template <typename U, typename V> Checked(const Checked<U, V>& rhs) 1.464 + { 1.465 + if (rhs.hasOverflowed()) 1.466 + this->overflowed(); 1.467 + if (!isInBounds<T>(rhs.m_value)) 1.468 + this->overflowed(); 1.469 + m_value = static_cast<T>(rhs.m_value); 1.470 + } 1.471 + 1.472 + const Checked& operator=(Checked rhs) 1.473 + { 1.474 + this->clearOverflow(); 1.475 + if (rhs.hasOverflowed()) 1.476 + this->overflowed(); 1.477 + m_value = static_cast<T>(rhs.m_value); 1.478 + return *this; 1.479 + } 1.480 + 1.481 + template <typename U> const Checked& operator=(U value) 1.482 + { 1.483 + return *this = Checked(value); 1.484 + } 1.485 + 1.486 + template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs) 1.487 + { 1.488 + return *this = Checked(rhs); 1.489 + } 1.490 + 1.491 + // prefix 1.492 + const Checked& operator++() 1.493 + { 1.494 + if (m_value == ::std::numeric_limits<T>::max()) 1.495 + this->overflowed(); 1.496 + m_value++; 1.497 + return *this; 1.498 + } 1.499 + 1.500 + const Checked& operator--() 1.501 + { 1.502 + if (m_value == ::std::numeric_limits<T>::min()) 1.503 + this->overflowed(); 1.504 + m_value--; 1.505 + return *this; 1.506 + } 1.507 + 1.508 + // postfix operators 1.509 + const Checked operator++(int) 1.510 + { 1.511 + if (m_value == ::std::numeric_limits<T>::max()) 1.512 + this->overflowed(); 1.513 + return Checked(m_value++); 1.514 + } 1.515 + 1.516 + const Checked operator--(int) 1.517 + { 1.518 + if (m_value == ::std::numeric_limits<T>::min()) 1.519 + this->overflowed(); 1.520 + return Checked(m_value--); 1.521 + } 1.522 + 1.523 + // Boolean operators 1.524 + bool operator!() const 1.525 + { 1.526 + if (this->hasOverflowed()) 1.527 + CRASH(); 1.528 + return !m_value; 1.529 + } 1.530 + 1.531 + typedef void* (Checked::*UnspecifiedBoolType); 1.532 + operator UnspecifiedBoolType*() const 1.533 + { 1.534 + if (this->hasOverflowed()) 1.535 + CRASH(); 1.536 + return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; 1.537 + } 1.538 + 1.539 + // Value accessors. unsafeGet() will crash if there's been an overflow. 1.540 + T unsafeGet() const 1.541 + { 1.542 + if (this->hasOverflowed()) 1.543 + CRASH(); 1.544 + return m_value; 1.545 + } 1.546 + 1.547 + bool safeGet(T& value) const WARN_UNUSED_RETURN 1.548 + { 1.549 + value = m_value; 1.550 + return this->hasOverflowed(); 1.551 + } 1.552 + 1.553 + // Mutating assignment 1.554 + template <typename U> const Checked operator+=(U rhs) 1.555 + { 1.556 + if (!safeAdd(m_value, rhs, m_value)) 1.557 + this->overflowed(); 1.558 + return *this; 1.559 + } 1.560 + 1.561 + template <typename U> const Checked operator-=(U rhs) 1.562 + { 1.563 + if (!safeSub(m_value, rhs, m_value)) 1.564 + this->overflowed(); 1.565 + return *this; 1.566 + } 1.567 + 1.568 + template <typename U> const Checked operator*=(U rhs) 1.569 + { 1.570 + if (!safeMultiply(m_value, rhs, m_value)) 1.571 + this->overflowed(); 1.572 + return *this; 1.573 + } 1.574 + 1.575 + const Checked operator*=(double rhs) 1.576 + { 1.577 + double result = rhs * m_value; 1.578 + // Handle +/- infinity and NaN 1.579 + if (!(::std::numeric_limits<T>::min() <= result && ::std::numeric_limits<T>::max() >= result)) 1.580 + this->overflowed(); 1.581 + m_value = (T)result; 1.582 + return *this; 1.583 + } 1.584 + 1.585 + const Checked operator*=(float rhs) 1.586 + { 1.587 + return *this *= (double)rhs; 1.588 + } 1.589 + 1.590 + template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs) 1.591 + { 1.592 + if (rhs.hasOverflowed()) 1.593 + this->overflowed(); 1.594 + return *this += rhs.m_value; 1.595 + } 1.596 + 1.597 + template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs) 1.598 + { 1.599 + if (rhs.hasOverflowed()) 1.600 + this->overflowed(); 1.601 + return *this -= rhs.m_value; 1.602 + } 1.603 + 1.604 + template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs) 1.605 + { 1.606 + if (rhs.hasOverflowed()) 1.607 + this->overflowed(); 1.608 + return *this *= rhs.m_value; 1.609 + } 1.610 + 1.611 + // Equality comparisons 1.612 + template <typename V> bool operator==(Checked<T, V> rhs) 1.613 + { 1.614 + return unsafeGet() == rhs.unsafeGet(); 1.615 + } 1.616 + 1.617 + template <typename U> bool operator==(U rhs) 1.618 + { 1.619 + if (this->hasOverflowed()) 1.620 + this->overflowed(); 1.621 + return safeEquals(m_value, rhs); 1.622 + } 1.623 + 1.624 + template <typename U, typename V> const Checked operator==(Checked<U, V> rhs) 1.625 + { 1.626 + return unsafeGet() == Checked(rhs.unsafeGet()); 1.627 + } 1.628 + 1.629 + template <typename U> bool operator!=(U rhs) 1.630 + { 1.631 + return !(*this == rhs); 1.632 + } 1.633 + 1.634 +private: 1.635 + // Disallow implicit conversion of floating point to integer types 1.636 + Checked(float); 1.637 + Checked(double); 1.638 + void operator=(float); 1.639 + void operator=(double); 1.640 + void operator+=(float); 1.641 + void operator+=(double); 1.642 + void operator-=(float); 1.643 + void operator-=(double); 1.644 + T m_value; 1.645 +}; 1.646 + 1.647 +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) 1.648 +{ 1.649 + U x = 0; 1.650 + V y = 0; 1.651 + bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); 1.652 + typename Result<U, V>::ResultType result = 0; 1.653 + overflowed |= !safeAdd(x, y, result); 1.654 + if (overflowed) 1.655 + return ResultOverflowed; 1.656 + return result; 1.657 +} 1.658 + 1.659 +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) 1.660 +{ 1.661 + U x = 0; 1.662 + V y = 0; 1.663 + bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); 1.664 + typename Result<U, V>::ResultType result = 0; 1.665 + overflowed |= !safeSub(x, y, result); 1.666 + if (overflowed) 1.667 + return ResultOverflowed; 1.668 + return result; 1.669 +} 1.670 + 1.671 +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) 1.672 +{ 1.673 + U x = 0; 1.674 + V y = 0; 1.675 + bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); 1.676 + typename Result<U, V>::ResultType result = 0; 1.677 + overflowed |= !safeMultiply(x, y, result); 1.678 + if (overflowed) 1.679 + return ResultOverflowed; 1.680 + return result; 1.681 +} 1.682 + 1.683 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs) 1.684 +{ 1.685 + return lhs + Checked<V, OverflowHandler>(rhs); 1.686 +} 1.687 + 1.688 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs) 1.689 +{ 1.690 + return lhs - Checked<V, OverflowHandler>(rhs); 1.691 +} 1.692 + 1.693 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs) 1.694 +{ 1.695 + return lhs * Checked<V, OverflowHandler>(rhs); 1.696 +} 1.697 + 1.698 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs) 1.699 +{ 1.700 + return Checked<U, OverflowHandler>(lhs) + rhs; 1.701 +} 1.702 + 1.703 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs) 1.704 +{ 1.705 + return Checked<U, OverflowHandler>(lhs) - rhs; 1.706 +} 1.707 + 1.708 +template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs) 1.709 +{ 1.710 + return Checked<U, OverflowHandler>(lhs) * rhs; 1.711 +} 1.712 + 1.713 +} 1.714 + 1.715 +using WTF::Checked; 1.716 +using WTF::RecordOverflow; 1.717 + 1.718 +#endif /* yarr_CheckedArithmetic_h */