From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WTF/wtf/CheckedArithmetic.h | 173 +++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 38 deletions(-) (limited to 'Source/WTF/wtf/CheckedArithmetic.h') diff --git a/Source/WTF/wtf/CheckedArithmetic.h b/Source/WTF/wtf/CheckedArithmetic.h index b58da2027..798d6f07c 100644 --- a/Source/WTF/wtf/CheckedArithmetic.h +++ b/Source/WTF/wtf/CheckedArithmetic.h @@ -75,11 +75,16 @@ class CrashOnOverflow { public: static NO_RETURN_DUE_TO_CRASH void overflowed() { - CRASH(); + crash(); } void clearOverflow() { } + static NO_RETURN_DUE_TO_CRASH void crash() + { + CRASH(); + } + public: bool hasOverflowed() const { return false; } }; @@ -101,6 +106,11 @@ protected: m_overflowed = false; } + static NO_RETURN_DUE_TO_CRASH void crash() + { + CRASH(); + } + public: bool hasOverflowed() const { return m_overflowed; } @@ -112,63 +122,84 @@ template class Checked; template struct RemoveChecked; template struct RemoveChecked>; -template ::is_signed, bool sourceSigned = std::numeric_limits::is_signed> struct BoundsChecker; -template struct BoundsChecker { +template = sizeof(Source), bool targetSigned = std::numeric_limits::is_signed, bool sourceSigned = std::numeric_limits::is_signed> struct BoundsChecker; +template struct BoundsChecker { static bool inBounds(Source value) { - // Same signedness so implicit type conversion will always increase precision - // to widest type + // Same signedness so implicit type conversion will always increase precision to widest type. return value <= std::numeric_limits::max(); } }; - -template struct BoundsChecker { +template struct BoundsChecker { static bool inBounds(Source value) { - // Same signedness so implicit type conversion will always increase precision - // to widest type + // Same signedness so implicit type conversion will always increase precision to widest type. return std::numeric_limits::min() <= value && value <= std::numeric_limits::max(); } }; -template struct BoundsChecker { +template struct BoundsChecker { static bool inBounds(Source value) { - // Target is unsigned so any value less than zero is clearly unsafe - if (value < 0) - return false; - // If our (unsigned) Target is the same or greater width we can - // convert value to type Target without losing precision - if (sizeof(Target) >= sizeof(Source)) - return static_cast(value) <= std::numeric_limits::max(); - // The signed Source type has greater precision than the target so - // max(Target) -> Source will widen. - return value <= static_cast(std::numeric_limits::max()); + // When converting value to unsigned Source, value will become a big value if value is negative. + // Casted value will become bigger than Target::max as Source is bigger than Target. + return static_cast::type>(value) <= std::numeric_limits::max(); } }; -template struct BoundsChecker { +template struct BoundsChecker { static bool inBounds(Source value) { - // Signed target with an unsigned source - if (sizeof(Target) <= sizeof(Source)) - return value <= static_cast(std::numeric_limits::max()); - // Target is Wider than Source so we're guaranteed to fit any value in - // unsigned Source + // The unsigned Source type has greater precision than the target so max(Target) -> Source will widen. + return value <= static_cast(std::numeric_limits::max()); + } +}; + +template struct BoundsChecker { + static bool inBounds(Source) + { + // Same sign, greater or same precision. return true; } }; -template ::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider; -template struct BoundsCheckElider { - static bool inBounds(Source) { return true; } +template struct BoundsChecker { + static bool inBounds(Source) + { + // Same sign, greater or same precision. + return true; + } }; -template struct BoundsCheckElider : public BoundsChecker { + +template struct BoundsChecker { + static bool inBounds(Source value) + { + // Target is signed with greater or same precision. If strictly greater, it is always safe. + if (sizeof(Target) > sizeof(Source)) + return true; + return value <= static_cast(std::numeric_limits::max()); + } +}; + +template struct BoundsChecker { + static bool inBounds(Source value) + { + // Target is unsigned with greater precision. + return value >= 0; + } }; template static inline bool isInBounds(Source value) { - return BoundsCheckElider::inBounds(value); + return BoundsChecker::inBounds(value); +} + +template static inline bool convertSafely(Source input, Target& output) +{ + if (!isInBounds(input)) + return false; + output = static_cast(input); + return true; } template struct RemoveChecked { @@ -517,23 +548,22 @@ public: bool operator!() const { if (this->hasOverflowed()) - CRASH(); + this->crash(); return !m_value; } - typedef void* (Checked::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const + explicit operator bool() const { if (this->hasOverflowed()) - CRASH(); - return (m_value) ? reinterpret_cast(1) : 0; + this->crash(); + return m_value; } // Value accessors. unsafeGet() will crash if there's been an overflow. T unsafeGet() const { if (this->hasOverflowed()) - CRASH(); + this->crash(); return m_value; } @@ -612,7 +642,7 @@ public: template bool operator==(U rhs) { if (this->hasOverflowed()) - this->overflowed(); + this->crash(); return safeEquals(m_value, rhs); } @@ -626,6 +656,47 @@ public: return !(*this == rhs); } + // Other comparisons + template bool operator<(Checked rhs) const + { + return unsafeGet() < rhs.unsafeGet(); + } + + bool operator<(T rhs) const + { + return unsafeGet() < rhs; + } + + template bool operator<=(Checked rhs) const + { + return unsafeGet() <= rhs.unsafeGet(); + } + + bool operator<=(T rhs) const + { + return unsafeGet() <= rhs; + } + + template bool operator>(Checked rhs) const + { + return unsafeGet() > rhs.unsafeGet(); + } + + bool operator>(T rhs) const + { + return unsafeGet() > rhs; + } + + template bool operator>=(Checked rhs) const + { + return unsafeGet() >= rhs.unsafeGet(); + } + + bool operator>=(T rhs) const + { + return unsafeGet() >= rhs; + } + private: // Disallow implicit conversion of floating point to integer types Checked(float); @@ -735,6 +806,30 @@ template bool sumOverflows(Args... args) return checkedSum(args...).hasOverflowed(); } +template bool differenceOverflows(U left, U right) +{ + return (Checked(left) - Checked(right)).hasOverflowed(); +} + +template +Checked checkedProduct(U value) +{ + return Checked(value); +} +template +Checked checkedProduct(U value, Args... args) +{ + return Checked(value) * checkedProduct(args...); +} + +// Sometimes, you just want to check if some math would overflow - the code to do the math is +// already in place, and you want to guard it. + +template bool productOverflows(Args... args) +{ + return checkedProduct(args...).hasOverflowed(); +} + } using WTF::Checked; @@ -750,6 +845,8 @@ using WTF::CheckedInt64; using WTF::CheckedUint64; using WTF::CheckedSize; using WTF::checkedSum; +using WTF::differenceOverflows; +using WTF::productOverflows; using WTF::sumOverflows; #endif -- cgit v1.2.1