From a804fd48b71679ece1f1c2284c3c1835c9e20441 Mon Sep 17 00:00:00 2001 From: tsepez Date: Fri, 21 Oct 2016 12:06:44 -0700 Subject: Fix some div by 0s in safe_math_impl.h The majority of these are already upstream in base/, the remainder will need upstreaming. Also pull some upstream changes to reduce diffing. Upstream CL is https://codereview.chromium.org/2440143003/ BUG=657436 Review-Url: https://chromiumcodereview.appspot.com/2441753003 --- third_party/base/numerics/safe_math_impl.h | 69 +++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) (limited to 'third_party') diff --git a/third_party/base/numerics/safe_math_impl.h b/third_party/base/numerics/safe_math_impl.h index f219cf52bb..959b7f1b61 100644 --- a/third_party/base/numerics/safe_math_impl.h +++ b/third_party/base/numerics/safe_math_impl.h @@ -5,8 +5,10 @@ #ifndef PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ +#include #include +#include #include #include #include @@ -90,13 +92,13 @@ template struct PositionOfSignBit { static const typename std::enable_if::is_integer, size_t>::type value = - 8 * sizeof(Integer) - 1; + CHAR_BIT * sizeof(Integer) - 1; }; // Helper templates for integer manipulations. template -bool HasSignBit(T x) { +constexpr bool HasSignBit(T x) { // Cast to unsigned since right shift on signed is undefined. return !!(static_cast::type>(x) >> PositionOfSignBit::value); @@ -104,8 +106,8 @@ bool HasSignBit(T x) { // This wrapper undoes the standard integer promotions. template -T BinaryComplement(T x) { - return ~x; +constexpr T BinaryComplement(T x) { + return static_cast(~x); } // Here are the actual portable checked integer math implementations. @@ -120,15 +122,16 @@ CheckedAdd(T x, T y, RangeConstraint* validity) { typedef typename UnsignedIntegerForSize::type UnsignedDst; UnsignedDst ux = static_cast(x); UnsignedDst uy = static_cast(y); - UnsignedDst uresult = ux + uy; + UnsignedDst uresult = static_cast(ux + uy); // Addition is valid if the sign of (x + y) is equal to either that of x or // that of y. if (std::numeric_limits::is_signed) { - if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) + if (HasSignBit(BinaryComplement( + static_cast((uresult ^ ux) & (uresult ^ uy))))) { *validity = RANGE_VALID; - else // Direction of wrap is inverse of result sign. + } else { // Direction of wrap is inverse of result sign. *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; - + } } else { // Unsigned is either valid or overflow. *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; } @@ -143,15 +146,16 @@ CheckedSub(T x, T y, RangeConstraint* validity) { typedef typename UnsignedIntegerForSize::type UnsignedDst; UnsignedDst ux = static_cast(x); UnsignedDst uy = static_cast(y); - UnsignedDst uresult = ux - uy; + UnsignedDst uresult = static_cast(ux - uy); // Subtraction is valid if either x and y have same sign, or (x-y) and x have // the same sign. if (std::numeric_limits::is_signed) { - if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) + if (HasSignBit(BinaryComplement( + static_cast((uresult ^ ux) & (ux ^ uy))))) { *validity = RANGE_VALID; - else // Direction of wrap is inverse of result sign. + } else { // Direction of wrap is inverse of result sign. *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; - + } } else { // Unsigned is either valid or underflow. *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; } @@ -182,26 +186,27 @@ typename std::enable_if::is_integer && CheckedMul(T x, T y, RangeConstraint* validity) { // If either side is zero then the result will be zero. if (!x || !y) { - return RANGE_VALID; - - } else if (x > 0) { - if (y > 0) + *validity = RANGE_VALID; + return static_cast(0); + } + if (x > 0) { + if (y > 0) { *validity = x <= std::numeric_limits::max() / y ? RANGE_VALID : RANGE_OVERFLOW; - else + } else { *validity = y >= std::numeric_limits::min() / x ? RANGE_VALID : RANGE_UNDERFLOW; - + } } else { - if (y > 0) + if (y > 0) { *validity = x >= std::numeric_limits::min() / y ? RANGE_VALID : RANGE_UNDERFLOW; - else + } else { *validity = y >= std::numeric_limits::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } } - - return x * y; + return static_cast(*validity == RANGE_VALID ? x * y : 0); } template @@ -213,24 +218,28 @@ CheckedMul(T x, T y, RangeConstraint* validity) { *validity = (y == 0 || x <= std::numeric_limits::max() / y) ? RANGE_VALID : RANGE_OVERFLOW; - return x * y; + return static_cast(*validity == RANGE_VALID ? x * y : 0); } -// Division just requires a check for an invalid negation on signed min/-1. +// Division just requires a check for a zero denominator or an invalid negation +// on signed min/-1. template T CheckedDiv(T x, T y, RangeConstraint* validity, typename std::enable_if::is_integer, int>::type = 0) { + if (y == 0) { + *validity = RANGE_INVALID; + return static_cast(0); + } if (std::numeric_limits::is_signed && x == std::numeric_limits::min() && y == static_cast(-1)) { *validity = RANGE_OVERFLOW; return std::numeric_limits::min(); } - *validity = RANGE_VALID; - return x / y; + return static_cast(x / y); } template @@ -239,7 +248,7 @@ typename std::enable_if::is_integer && T>::type CheckedMod(T x, T y, RangeConstraint* validity) { *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; - return x % y; + return static_cast(*validity == RANGE_VALID ? x % y : 0); } template @@ -247,8 +256,8 @@ typename std::enable_if::is_integer && !std::numeric_limits::is_signed, T>::type CheckedMod(T x, T y, RangeConstraint* validity) { - *validity = RANGE_VALID; - return x % y; + *validity = y != 0 ? RANGE_VALID : RANGE_INVALID; + return static_cast(*validity == RANGE_VALID ? x % y : 0); } template @@ -300,7 +309,7 @@ CheckedAbs(T value, RangeConstraint* validity) { typename std::enable_if::is_iec559, T>::type \ Checked##NAME(T, T, RangeConstraint*) { \ NOTREACHED(); \ - return 0; \ + return static_cast(0); \ } BASE_FLOAT_ARITHMETIC_STUBS(Add) -- cgit v1.2.3