summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--third_party/base/numerics/safe_math_impl.h69
1 files changed, 39 insertions, 30 deletions
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 <stddef.h>
#include <stdint.h>
+#include <climits>
#include <cmath>
#include <cstdlib>
#include <limits>
@@ -90,13 +92,13 @@ template <typename Integer>
struct PositionOfSignBit {
static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
size_t>::type value =
- 8 * sizeof(Integer) - 1;
+ CHAR_BIT * sizeof(Integer) - 1;
};
// Helper templates for integer manipulations.
template <typename T>
-bool HasSignBit(T x) {
+constexpr bool HasSignBit(T x) {
// Cast to unsigned since right shift on signed is undefined.
return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
PositionOfSignBit<T>::value);
@@ -104,8 +106,8 @@ bool HasSignBit(T x) {
// This wrapper undoes the standard integer promotions.
template <typename T>
-T BinaryComplement(T x) {
- return ~x;
+constexpr T BinaryComplement(T x) {
+ return static_cast<T>(~x);
}
// Here are the actual portable checked integer math implementations.
@@ -120,15 +122,16 @@ CheckedAdd(T x, T y, RangeConstraint* validity) {
typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
UnsignedDst ux = static_cast<UnsignedDst>(x);
UnsignedDst uy = static_cast<UnsignedDst>(y);
- UnsignedDst uresult = ux + uy;
+ UnsignedDst uresult = static_cast<UnsignedDst>(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<T>::is_signed) {
- if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
+ if (HasSignBit(BinaryComplement(
+ static_cast<UnsignedDst>((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<T>::type UnsignedDst;
UnsignedDst ux = static_cast<UnsignedDst>(x);
UnsignedDst uy = static_cast<UnsignedDst>(y);
- UnsignedDst uresult = ux - uy;
+ UnsignedDst uresult = static_cast<UnsignedDst>(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<T>::is_signed) {
- if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
+ if (HasSignBit(BinaryComplement(
+ static_cast<UnsignedDst>((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<std::numeric_limits<T>::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<T>(0);
+ }
+ if (x > 0) {
+ if (y > 0) {
*validity =
x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
- else
+ } else {
*validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
: RANGE_UNDERFLOW;
-
+ }
} else {
- if (y > 0)
+ if (y > 0) {
*validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
: RANGE_UNDERFLOW;
- else
+ } else {
*validity =
y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
+ }
}
-
- return x * y;
+ return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
}
template <typename T>
@@ -213,24 +218,28 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
*validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
? RANGE_VALID
: RANGE_OVERFLOW;
- return x * y;
+ return static_cast<T>(*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 <typename T>
T CheckedDiv(T x,
T y,
RangeConstraint* validity,
typename std::enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0) {
+ if (y == 0) {
+ *validity = RANGE_INVALID;
+ return static_cast<T>(0);
+ }
if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
y == static_cast<T>(-1)) {
*validity = RANGE_OVERFLOW;
return std::numeric_limits<T>::min();
}
-
*validity = RANGE_VALID;
- return x / y;
+ return static_cast<T>(x / y);
}
template <typename T>
@@ -239,7 +248,7 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
- return x % y;
+ return static_cast<T>(*validity == RANGE_VALID ? x % y : 0);
}
template <typename T>
@@ -247,8 +256,8 @@ typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::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<T>(*validity == RANGE_VALID ? x % y : 0);
}
template <typename T>
@@ -300,7 +309,7 @@ CheckedAbs(T value, RangeConstraint* validity) {
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
Checked##NAME(T, T, RangeConstraint*) { \
NOTREACHED(); \
- return 0; \
+ return static_cast<T>(0); \
}
BASE_FLOAT_ARITHMETIC_STUBS(Add)