From bacd62cae0043e2c4f98cc5e728d8f458b20e8d8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 11 May 2026 14:00:51 +1000 Subject: [PATCH] util: fix xatou_base for values > UINT_MAX The check `(long)v < 0` only catches values >= LONG_MAX when cast to signed long. On 64-bit systems where sizeof(long) == 8, values between UINT_MAX+1 and LONG_MAX pass this check but silently truncate when assigned to the unsigned int output parameter. Use `v > UINT_MAX` for a correct range check. Assisted-by: Claude:claude-opus-4-6 Part-of: --- src/util-strings.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ src/util-strings.h | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/util-strings.c b/src/util-strings.c index 71a3387..41c1d95 100644 --- a/src/util-strings.c +++ b/src/util-strings.c @@ -658,4 +658,70 @@ MUNIT_TEST(test_strv_from_mem) return MUNIT_OK; } + +MUNIT_TEST(test_xatou) +{ + unsigned int val; + + munit_assert_true(xatou("0", &val)); + munit_assert_uint(val, ==, 0); + + munit_assert_true(xatou("1", &val)); + munit_assert_uint(val, ==, 1); + + munit_assert_true(xatou("123", &val)); + munit_assert_uint(val, ==, 123); + + /* UINT_MAX is the upper boundary, must succeed */ + munit_assert_true(xatou("4294967295", &val)); + munit_assert_uint(val, ==, UINT_MAX); + + /* UINT_MAX + 1 must fail */ + munit_assert_false(xatou("4294967296", &val)); + + /* Another random value in the range UINT_MAX < val < LONG_MAX */ + munit_assert_false(xatou("8589934592", &val)); + + /* LONG_MAX as string - must fail */ + munit_assert_false(xatou("9223372036854775807", &val)); + + /* Overflow beyond ULONG_MAX - strtoul sets errno, must fail */ + munit_assert_false(xatou("18446744073709551616", &val)); + + /* negative numbers: strtoul wraps "-1" to ULONG_MAX without + * setting errno, but v > UINT_MAX catches it */ + munit_assert_false(xatou("-1", &val)); + + /* invalid strings */ + munit_assert_false(xatou("", &val)); + munit_assert_false(xatou("abc", &val)); + munit_assert_false(xatou("123abc", &val)); + munit_assert_false(xatou("12 34", &val)); + + /* hex via xatou_base */ + munit_assert_true(xatou_base("ff", &val, 16)); + munit_assert_uint(val, ==, 0xff); + + munit_assert_true(xatou_base("0xff", &val, 16)); + munit_assert_uint(val, ==, 0xff); + + munit_assert_true(xatou_base("FFFFFFFF", &val, 16)); + munit_assert_uint(val, ==, UINT_MAX); + + /* hex UINT_MAX + 1 */ + munit_assert_false(xatou_base("100000000", &val, 16)); + + /* octal */ + munit_assert_true(xatou_base("77", &val, 8)); + munit_assert_uint(val, ==, 077); + + munit_assert_true(xatou_base("37777777777", &val, 8)); + munit_assert_uint(val, ==, UINT_MAX); + + /* octal UINT_MAX + 1 */ + munit_assert_false(xatou_base("40000000000", &val, 8)); + + return MUNIT_OK; +} + #endif diff --git a/src/util-strings.h b/src/util-strings.h index f82874d..e62df4c 100644 --- a/src/util-strings.h +++ b/src/util-strings.h @@ -183,7 +183,7 @@ xatou_base(const char *str, unsigned int *val, int base) if (*str != '\0' && *endptr != '\0') return false; - if ((long)v < 0) + if (v > UINT_MAX) return false; *val = v;