Switch from int to ptrdiff_t in absl/strings/internal/charconv_parse.cc This avoids the potential for integer- and buffer-overflows. PiperOrigin-RevId: 944848464 Change-Id: I2f0278684171ead46b650d0241807c182c05d033
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc index 98823de..2766cf3 100644 --- a/absl/strings/internal/charconv_parse.cc +++ b/absl/strings/internal/charconv_parse.cc
@@ -13,12 +13,13 @@ // limitations under the License. #include "absl/strings/internal/charconv_parse.h" -#include "absl/strings/charconv.h" #include <cassert> +#include <cstddef> #include <cstdint> #include <limits> +#include "absl/strings/charconv.h" #include "absl/strings/internal/memutil.h" namespace absl { @@ -246,8 +247,9 @@ // ConsumeDigits does not protect against overflow on *out; max_digits must // be chosen with respect to type T to avoid the possibility of overflow. template <int base, typename T> -int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out, - bool* dropped_nonzero_digit) { +ptrdiff_t ConsumeDigits(const char* begin, const char* end, + ptrdiff_t max_digits, T* out, + bool* dropped_nonzero_digit) { if (base == 10) { assert(max_digits <= std::numeric_limits<T>::digits10); } else if (base == 16) { @@ -282,7 +284,7 @@ *dropped_nonzero_digit = true; } *out = accumulator; - return static_cast<int>(begin - original_begin); + return begin - original_begin; } // Returns true if `v` is one of the chars allowed inside parentheses following @@ -370,24 +372,22 @@ } uint64_t mantissa = 0; - int exponent_adjustment = 0; + ptrdiff_t exponent_adjustment = 0; bool mantissa_is_inexact = false; - int pre_decimal_digits = ConsumeDigits<base>( + ptrdiff_t pre_decimal_digits = ConsumeDigits<base>( begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact); begin += pre_decimal_digits; - int digits_left; + ptrdiff_t digits_left; if (pre_decimal_digits >= DigitLimit<base>()) { // refuse to parse pathological inputs return result; } else if (pre_decimal_digits > MantissaDigitsMax<base>()) { // We dropped some non-fraction digits on the floor. Adjust our exponent // to compensate. - exponent_adjustment = - static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>()); + exponent_adjustment = pre_decimal_digits - MantissaDigitsMax<base>(); digits_left = 0; } else { - digits_left = - static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits); + digits_left = MantissaDigitsMax<base>() - pre_decimal_digits; } if (begin < end && *begin == '.') { ++begin; @@ -398,14 +398,14 @@ while (begin < end && *begin == '0') { ++begin; } - int zeros_skipped = static_cast<int>(begin - begin_zeros); + ptrdiff_t zeros_skipped = begin - begin_zeros; if (zeros_skipped >= DigitLimit<base>()) { // refuse to parse pathological inputs return result; } - exponent_adjustment -= static_cast<int>(zeros_skipped); + exponent_adjustment -= zeros_skipped; } - int post_decimal_digits = ConsumeDigits<base>( + ptrdiff_t post_decimal_digits = ConsumeDigits<base>( begin, end, digits_left, &mantissa, &mantissa_is_inexact); begin += post_decimal_digits; @@ -482,15 +482,26 @@ return result; } - // Success! - result.type = strings_internal::FloatType::kNumber; if (result.mantissa > 0) { - result.exponent = result.literal_exponent + - (DigitMagnitude<base>() * exponent_adjustment); + const ptrdiff_t exponent = result.literal_exponent + + (DigitMagnitude<base>() * exponent_adjustment); + + if (exponent < (std::numeric_limits<int>::min)() || + exponent > (std::numeric_limits<int>::max)()) { + // We cannot store the exponent in int. Fail by returning a result with + // end default-initialized to nullptr. + return result; + } + + result.exponent = static_cast<int>(exponent); } else { result.exponent = 0; } result.end = begin; + + // Success! + result.type = strings_internal::FloatType::kNumber; + return result; }