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: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/388>
This commit is contained in:
Peter Hutterer 2026-05-11 14:00:51 +10:00 committed by Marge Bot
parent bbcc808b1a
commit bacd62cae0
2 changed files with 67 additions and 1 deletions

View file

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

View file

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