Fix outputting extreme integer values in edge cases
For some gcc version (Ubuntu 5.5.0-12ubuntu1~16.04) the existing code
crashes when the minimum value of int64_t is outputted.
Resurrect the code from before 546e2cbf
(🚨 fixed some warnings,
2019-03-13) but delegate the sign removal so that the compilers don't
complain about taking the negative value of an unsigned value.
In addition we also rewrite the expression so that we first increment
and then negate.
The definition of remove_sign(number_unsigned_t) is never called as
unsigned values are never negative.
This commit is contained in:
parent
bf4156056b
commit
6ce2f35ba8
2 changed files with 54 additions and 2 deletions
|
@ -630,7 +630,7 @@ class serializer
|
|||
if (is_negative)
|
||||
{
|
||||
*buffer_ptr = '-';
|
||||
abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
|
||||
abs_value = remove_sign(x);
|
||||
|
||||
// account one more byte for the minus sign
|
||||
n_chars = 1 + count_digits(abs_value);
|
||||
|
@ -811,6 +811,32 @@ class serializer
|
|||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overload to make the compiler happy while it is instantiating
|
||||
* dump_integer for number_unsigned_t.
|
||||
* Must never be called.
|
||||
*/
|
||||
number_unsigned_t remove_sign(number_unsigned_t x)
|
||||
{
|
||||
assert(false); // LCOV_EXCL_LINE
|
||||
return x; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for dump_integer
|
||||
*
|
||||
* This function takes a negative signed integer and returns its absolute
|
||||
* value as unsigned integer. The plus/minus shuffling is necessary as we can
|
||||
* not directly remove the sign of an arbitrary signed integer as the
|
||||
* absolute values of INT_MIN and INT_MAX are usually not the same. See
|
||||
* #1708 for details.
|
||||
*/
|
||||
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
|
||||
{
|
||||
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
|
||||
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
|
||||
}
|
||||
|
||||
private:
|
||||
/// the output of the serializer
|
||||
output_adapter_t<char> o = nullptr;
|
||||
|
|
|
@ -14264,7 +14264,7 @@ class serializer
|
|||
if (is_negative)
|
||||
{
|
||||
*buffer_ptr = '-';
|
||||
abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
|
||||
abs_value = remove_sign(x);
|
||||
|
||||
// account one more byte for the minus sign
|
||||
n_chars = 1 + count_digits(abs_value);
|
||||
|
@ -14445,6 +14445,32 @@ class serializer
|
|||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overload to make the compiler happy while it is instantiating
|
||||
* dump_integer for number_unsigned_t.
|
||||
* Must never be called.
|
||||
*/
|
||||
number_unsigned_t remove_sign(number_unsigned_t x)
|
||||
{
|
||||
assert(false); // LCOV_EXCL_LINE
|
||||
return x; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for dump_integer
|
||||
*
|
||||
* This function takes a negative signed integer and returns its absolute
|
||||
* value as unsigned integer. The plus/minus shuffling is necessary as we can
|
||||
* not directly remove the sign of an arbitrary signed integer as the
|
||||
* absolute values of INT_MIN and INT_MAX are usually not the same. See
|
||||
* #1708 for details.
|
||||
*/
|
||||
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
|
||||
{
|
||||
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
|
||||
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
|
||||
}
|
||||
|
||||
private:
|
||||
/// the output of the serializer
|
||||
output_adapter_t<char> o = nullptr;
|
||||
|
|
Loading…
Reference in a new issue