While we were matching 32-bit strtol in qemu_strtoi, our use of a 64-bit parse was leaking through for some inaccurate answers in qemu_strtoui in comparison to a 32-bit strtoul. Fix those, and update the testsuite now that our bounds checks are correct.
Our int wrappers would be a lot easier to write if libc had a guaranteed 32-bit parser even on platforms with 64-bit long. Fixes: 473a2a331e ("cutils: add qemu_strtoi & qemu_strtoui parsers for int/unsigned int types", v2.12.0) Signed-off-by: Eric Blake <ebl...@redhat.com> --- tests/unit/test-cutils.c | 11 +++++------ util/cutils.c | 14 ++++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 89c10f5307a..08989d1d3ac 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -858,7 +858,7 @@ static void test_qemu_strtoui_hex(void) static void test_qemu_strtoui_wrap(void) { - /* FIXME - wraparound should be consistent with 32-bit strtoul */ + /* wraparound is consistent with 32-bit strtoul */ const char *str = "-4294967295"; /* 1 mod 2^32 */ char f = 'X'; const char *endptr = &f; @@ -867,8 +867,8 @@ static void test_qemu_strtoui_wrap(void) err = qemu_strtoui(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, -ERANGE /* FIXME 0 */); - g_assert_cmphex(res, ==, UINT_MAX /* FIXME 1 */); + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 1); g_assert_true(endptr == str + strlen(str)); } @@ -935,13 +935,12 @@ static void test_qemu_strtoui_underflow(void) g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); - /* FIXME - overflow should be consistent with 32-bit strtoul */ str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */ endptr = "somewhere"; res = 999; err = qemu_strtoui(str, &endptr, 0, &res); - g_assert_cmpint(err, ==, 0 /* FIXME -ERANGE */); - g_assert_cmpint(res, ==, 1 /* FIXME UINT_MAX */); + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, UINT_MAX); g_assert_true(endptr == str + strlen(str)); str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */ diff --git a/util/cutils.c b/util/cutils.c index 5887e744140..997ddcd09e5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -466,10 +466,16 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base, if (errno == ERANGE) { *result = -1; } else { - if (lresult > UINT_MAX) { - *result = UINT_MAX; - errno = ERANGE; - } else if (lresult < INT_MIN) { + /* + * Note that platforms with 32-bit strtoul accept input in the + * range [-4294967295, 4294967295]; but we used 64-bit + * strtoull which wraps -18446744073709551615 to 1. Reject + * positive values that contain '-', and wrap all valid + * negative values. + */ + if (lresult > UINT_MAX || + lresult < -(long long)UINT_MAX || + (lresult > 0 && memchr(nptr, '-', ep - nptr))) { *result = UINT_MAX; errno = ERANGE; } else { -- 2.40.1