Index: base/numerics/checked_math_impl.h |
diff --git a/base/numerics/checked_math_impl.h b/base/numerics/checked_math_impl.h |
index 0492d1dbb5540e4f7a90a51bf4217a0a07388b27..bf3a3077efb75341285c7a480f757839238f8d83 100644 |
--- a/base/numerics/checked_math_impl.h |
+++ b/base/numerics/checked_math_impl.h |
@@ -182,17 +182,19 @@ struct CheckedMulOp<T, |
return !__builtin_mul_overflow(x, y, result); |
#endif |
using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type; |
+ // Verify the destination type can hold the result (always true for 0). |
+ if (!(IsValueInRangeForNumericType<Promotion>(x) && |
+ IsValueInRangeForNumericType<Promotion>(y)) && |
+ x && y) { |
+ return false; |
+ } |
Promotion presult; |
- // Fail if either operand is out of range for the promoted type. |
- // TODO(jschuh): This could be made to work for a broader range of values. |
- bool is_valid = IsValueInRangeForNumericType<Promotion>(x) && |
- IsValueInRangeForNumericType<Promotion>(y); |
- |
+ bool is_valid = true; |
if (IsIntegerArithmeticSafe<Promotion, T, U>::value) { |
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); |
} else { |
- is_valid &= CheckedMulImpl(static_cast<Promotion>(x), |
- static_cast<Promotion>(y), &presult); |
+ is_valid = CheckedMulImpl(static_cast<Promotion>(x), |
+ static_cast<Promotion>(y), &presult); |
} |
*result = static_cast<V>(presult); |
return is_valid && IsValueInRangeForNumericType<V>(presult); |
@@ -242,7 +244,7 @@ struct CheckedDivOp<T, |
template <typename T> |
bool CheckedModImpl(T x, T y, T* result) { |
static_assert(std::is_integral<T>::value, "Type must be integral"); |
- if (y > 0) { |
+ if (y) { |
*result = static_cast<T>(x % y); |
return true; |
} |
@@ -283,15 +285,15 @@ struct CheckedLshOp<T, |
using result_type = T; |
template <typename V> |
static bool Do(T x, U shift, V* result) { |
- using ShiftType = typename std::make_unsigned<T>::type; |
- static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value; |
- const ShiftType real_shift = static_cast<ShiftType>(shift); |
// Signed shift is not legal on negative values. |
- if (!IsValueNegative(x) && real_shift < kBitWidth) { |
+ if (!IsValueNegative(x) && |
+ as_unsigned(shift) < IntegerBitsPlusSign<T>::value) { |
// Just use a multiplication because it's easy. |
// TODO(jschuh): This could probably be made more efficient. |
- if (!std::is_signed<T>::value || real_shift != kBitWidth - 1) |
- return CheckedMulOp<T, T>::Do(x, static_cast<T>(1) << shift, result); |
+ if (!std::is_signed<T>::value || |
+ as_unsigned(shift) < std::numeric_limits<T>::digits) |
+ return CheckedMulOp<T, T>::Do(x, T(1) << shift, result); |
+ *result = 0; |
return !x; // Special case zero for a full width signed shift. |
} |
return false; |
@@ -313,8 +315,7 @@ struct CheckedRshOp<T, |
template <typename V> |
static bool Do(T x, U shift, V* result) { |
// Use the type conversion push negative values out of range. |
- using ShiftType = typename std::make_unsigned<T>::type; |
- if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) { |
+ if (as_unsigned(shift) < IntegerBitsPlusSign<T>::value) { |
T tmp = x >> shift; |
*result = static_cast<V>(tmp); |
return IsValueInRangeForNumericType<V>(tmp); |