mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-10-28 18:07:16 +08:00
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:
parent
f3f02c8ad0
commit
1271675129
@ -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))
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user