| 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);
|
|
|