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:
rootvector2 2026-05-21 21:14:57 +05:30
parent a3a21b31ef
commit a63865f58a
1 changed files with 5 additions and 1 deletions

View File

@ -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
{