mirror of https://github.com/jarro2783/cxxopts.git
Avoid undefined std::abs(INT_MIN) in integer_parser
When parsing a negative integer into a signed type whose minimum value equals INTMAX_MIN (e.g. int64_t on typical platforms), integer_parser computes the limit as std::abs(static_cast<intmax_t>(min())). Negating INTMAX_MIN cannot be represented in intmax_t, so the std::abs call is undefined behaviour. UBSan flags this on every negative int64_t parse, including a trivial one like "-1": runtime error: negation of -9223372036854775808 cannot be represented in type 'long'; cast to an unsigned type to negate this value to itself Build the same unsigned magnitude (|min| == max + 1 for two's-complement) directly in the unsigned arithmetic type instead. For unsigned T the expression wraps to 0, which matches the previous std::abs(0) value, so behaviour for unsigned types is preserved.
This commit is contained in:
parent
a3a21b31ef
commit
a63865f58a
|
|
@ -1057,7 +1057,11 @@ integer_parser(const std::string& text, T& value)
|
|||
US limit = 0;
|
||||
if (negative)
|
||||
{
|
||||
limit = static_cast<US>(std::abs(static_cast<intmax_t>((std::numeric_limits<T>::min)())));
|
||||
// |min| equals max + 1 for two's-complement signed types; computing it
|
||||
// via std::abs(min) is undefined behaviour (e.g. abs(INT64_MIN)). Build
|
||||
// the same value in unsigned arithmetic instead. For unsigned T this
|
||||
// intentionally wraps to 0, matching the previous std::abs(0) result.
|
||||
limit = static_cast<US>(static_cast<US>((std::numeric_limits<T>::max)()) + US{1});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue