avoid signed negation overflow in integer_times_pow10

Negating the most negative int64_t is undefined behaviour. GCC at -O2 uses that to turn the fast-path mantissa bound into a signed compare and returns the wrong sign, so take the magnitude in uint64_t instead.
This commit is contained in:
Sahana Bogar 2026-10-05 22:46:40 +05:30
parent f3f02c8ad0
commit 1271675129
2 changed files with 7 additions and 1 deletions

View File

@ -503,7 +503,9 @@ FASTFLOAT_CONSTEXPR20
typename std::enable_if<is_supported_float_type<T>::value, T>::type
integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept {
const bool is_negative = mantissa < 0;
const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa);
// Negate as unsigned: -mantissa overflows for the most negative int64_t.
const uint64_t m = is_negative ? uint64_t(0) - static_cast<uint64_t>(mantissa)
: static_cast<uint64_t>(mantissa);
T value;
if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value))

View File

@ -2485,6 +2485,10 @@ TEST_CASE("integer_times_pow10") {
all::verify_integer_times_pow10(12345678901234567890ull, -42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::max(), -42);
// the most negative int64_t has no positive counterpart to negate into
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::min(), 0);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::min(), 42);
all::verify_integer_times_pow10(std::numeric_limits<int64_t>::min(), -42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), 42);
all::verify_integer_times_pow10(std::numeric_limits<uint64_t>::max(), -42);
}