From 6162f7dafef51b44c5700ac3f82ff682faafe6c2 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 23 Mar 2021 16:53:00 +0000 Subject: [PATCH] utils: Work around mingw strto*l bug with 0x MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Mingw recognizes that "0x" has value 0 without setting errno, but fails to advance endptr to the trailing garbage 'x'. This in turn showed up in our recent testsuite additions for qemu_strtosz (commit 1657ba44b4 utils: Enhance testsuite for do_strtosz()); adjust our remaining tests to show that we now work around this windows bug. This patch intentionally fails check-syntax for use of strtol. Signed-off-by: Eric Blake Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20210317143325.2165821-3-eblake@redhat.com> Message-Id: <20210323165308.15244-15-alex.bennee@linaro.org> --- tests/unit/test-cutils.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 29 +++++++++++++++++++------- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/tests/unit/test-cutils.c b/tests/unit/test-cutils.c index 5908de4fd0..98671f1ac3 100644 --- a/tests/unit/test-cutils.c +++ b/tests/unit/test-cutils.c @@ -378,6 +378,15 @@ static void test_qemu_strtoi_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + res = 999; + endptr = &f; + err = qemu_strtoi(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtoi_max(void) @@ -669,6 +678,15 @@ static void test_qemu_strtoui_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + res = 999; + endptr = &f; + err = qemu_strtoui(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtoui_max(void) @@ -955,6 +973,15 @@ static void test_qemu_strtol_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtol_max(void) @@ -1244,6 +1271,15 @@ static void test_qemu_strtoul_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtoul_max(void) @@ -1528,6 +1564,15 @@ static void test_qemu_strtoi64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + endptr = &f; + res = 999; + err = qemu_strtoi64(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtoi64_max(void) @@ -1815,6 +1860,15 @@ static void test_qemu_strtou64_hex(void) g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); + + str = "0x"; + endptr = &f; + res = 999; + err = qemu_strtou64(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmphex(res, ==, 0); + g_assert(endptr == str + 1); } static void test_qemu_strtou64_max(void) diff --git a/util/cutils.c b/util/cutils.c index b425ed6570..ee908486da 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -396,9 +396,22 @@ int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result) * Helper function for error checking after strtol() and the like */ static int check_strtox_error(const char *nptr, char *ep, - const char **endptr, int libc_errno) + const char **endptr, bool check_zero, + int libc_errno) { assert(ep >= nptr); + + /* Windows has a bug in that it fails to parse 0 from "0x" in base 16 */ + if (check_zero && ep == nptr && libc_errno == 0) { + char *tmp; + + errno = 0; + if (strtol(nptr, &tmp, 10) == 0 && errno == 0 && + (*tmp == 'x' || *tmp == 'X')) { + ep = tmp; + } + } + if (endptr) { *endptr = ep; } @@ -465,7 +478,7 @@ int qemu_strtoi(const char *nptr, const char **endptr, int base, } else { *result = lresult; } - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, lresult == 0, errno); } /** @@ -524,7 +537,7 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base, *result = lresult; } } - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, lresult == 0, errno); } /** @@ -566,7 +579,7 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, errno = 0; *result = strtol(nptr, &ep, base); - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } /** @@ -613,7 +626,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, if (errno == ERANGE) { *result = -1; } - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } /** @@ -639,7 +652,7 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, QEMU_BUILD_BUG_ON(sizeof(int64_t) != sizeof(long long)); errno = 0; *result = strtoll(nptr, &ep, base); - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } /** @@ -668,7 +681,7 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, if (errno == ERANGE) { *result = -1; } - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } /** @@ -708,7 +721,7 @@ int qemu_strtod(const char *nptr, const char **endptr, double *result) errno = 0; *result = strtod(nptr, &ep); - return check_strtox_error(nptr, ep, endptr, errno); + return check_strtox_error(nptr, ep, endptr, false, errno); } /** -- 2.11.0