From a63865f58ae1e0c84929781199078179a53ddb41 Mon Sep 17 00:00:00 2001 From: rootvector2 Date: Thu, 21 May 2026 21:14:57 +0530 Subject: [PATCH] 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(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. --- include/cxxopts.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 891e78a..6bf57a6 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1057,7 +1057,11 @@ integer_parser(const std::string& text, T& value) US limit = 0; if (negative) { - limit = static_cast(std::abs(static_cast((std::numeric_limits::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(static_cast((std::numeric_limits::max)()) + US{1}); } else {