mirror of https://github.com/xemu-project/xemu.git
cutils: Allow NULL endptr in parse_uint()
All the qemu_strto*() functions permit a NULL endptr, just like their libc counterparts, leaving parse_uint() as the oddball that caused SEGFAULT on NULL and required the user to call parse_uint_full() instead. Relax things for consistency, even though the testsuite is the only impacted caller. Add one more unit test to ensure even parse_uint_full(NULL, 0, &value) works. This also fixes our code to uniformly favor EINVAL over ERANGE when both apply. Also fixes a doc mismatch @v vs. a parameter named value. Signed-off-by: Eric Blake <eblake@redhat.com> Reviewed-by: Hanna Czenczek <hreitz@redhat.com> Message-Id: <20230522190441.64278-9-eblake@redhat.com>
This commit is contained in:
parent
bd1386cce1
commit
52d606aa5b
|
@ -270,14 +270,26 @@ static void test_parse_uint_full_correct(void)
|
||||||
|
|
||||||
static void test_parse_uint_full_erange_junk(void)
|
static void test_parse_uint_full_erange_junk(void)
|
||||||
{
|
{
|
||||||
/* FIXME - inconsistent with qemu_strto* which favors EINVAL */
|
/* EINVAL has priority over ERANGE */
|
||||||
uint64_t i = 999;
|
uint64_t i = 999;
|
||||||
const char *str = "-2junk";
|
const char *str = "-2junk";
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = parse_uint_full(str, 0, &i);
|
r = parse_uint_full(str, 0, &i);
|
||||||
|
|
||||||
g_assert_cmpint(r, ==, -ERANGE /* FIXME -EINVAL */);
|
g_assert_cmpint(r, ==, -EINVAL);
|
||||||
|
g_assert_cmpuint(i, ==, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_parse_uint_full_null(void)
|
||||||
|
{
|
||||||
|
uint64_t i = 999;
|
||||||
|
const char *str = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = parse_uint_full(str, 0, &i);
|
||||||
|
|
||||||
|
g_assert_cmpint(r, ==, -EINVAL);
|
||||||
g_assert_cmpuint(i, ==, 0);
|
g_assert_cmpuint(i, ==, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3328,6 +3340,8 @@ int main(int argc, char **argv)
|
||||||
test_parse_uint_full_correct);
|
test_parse_uint_full_correct);
|
||||||
g_test_add_func("/cutils/parse_uint_full/erange_junk",
|
g_test_add_func("/cutils/parse_uint_full/erange_junk",
|
||||||
test_parse_uint_full_erange_junk);
|
test_parse_uint_full_erange_junk);
|
||||||
|
g_test_add_func("/cutils/parse_uint_full/null",
|
||||||
|
test_parse_uint_full_null);
|
||||||
|
|
||||||
/* qemu_strtoi() tests */
|
/* qemu_strtoi() tests */
|
||||||
g_test_add_func("/cutils/qemu_strtoi/correct",
|
g_test_add_func("/cutils/qemu_strtoi/correct",
|
||||||
|
|
|
@ -722,8 +722,7 @@ const char *qemu_strchrnul(const char *s, int c)
|
||||||
* parse_uint:
|
* parse_uint:
|
||||||
*
|
*
|
||||||
* @s: String to parse
|
* @s: String to parse
|
||||||
* @endptr: Destination for pointer to first character not consumed, must
|
* @endptr: Destination for pointer to first character not consumed
|
||||||
* not be %NULL
|
|
||||||
* @base: integer base, between 2 and 36 inclusive, or 0
|
* @base: integer base, between 2 and 36 inclusive, or 0
|
||||||
* @value: Destination for parsed integer value
|
* @value: Destination for parsed integer value
|
||||||
*
|
*
|
||||||
|
@ -737,7 +736,8 @@ const char *qemu_strchrnul(const char *s, int c)
|
||||||
*
|
*
|
||||||
* Set *@endptr to point right beyond the parsed integer (even if the integer
|
* Set *@endptr to point right beyond the parsed integer (even if the integer
|
||||||
* overflows or is negative, all digits will be parsed and *@endptr will
|
* overflows or is negative, all digits will be parsed and *@endptr will
|
||||||
* point right beyond them).
|
* point right beyond them). If @endptr is %NULL, any trailing character
|
||||||
|
* instead causes a result of -EINVAL with *@value of 0.
|
||||||
*
|
*
|
||||||
* If the integer is negative, set *@value to 0, and return -ERANGE.
|
* If the integer is negative, set *@value to 0, and return -ERANGE.
|
||||||
* (If you want to allow negative numbers that wrap around within
|
* (If you want to allow negative numbers that wrap around within
|
||||||
|
@ -784,7 +784,12 @@ int parse_uint(const char *s, const char **endptr, int base, uint64_t *value)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*value = val;
|
*value = val;
|
||||||
*endptr = endp;
|
if (endptr) {
|
||||||
|
*endptr = endp;
|
||||||
|
} else if (s && *endp) {
|
||||||
|
r = -EINVAL;
|
||||||
|
*value = 0;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,28 +800,13 @@ out:
|
||||||
* @base: integer base, between 2 and 36 inclusive, or 0
|
* @base: integer base, between 2 and 36 inclusive, or 0
|
||||||
* @value: Destination for parsed integer value
|
* @value: Destination for parsed integer value
|
||||||
*
|
*
|
||||||
* Parse unsigned integer from entire string
|
* Parse unsigned integer from entire string, rejecting any trailing slop.
|
||||||
*
|
*
|
||||||
* Have the same behavior of parse_uint(), but with an additional
|
* Shorthand for parse_uint(s, NULL, base, value).
|
||||||
* check for additional data after the parsed number. If extra
|
|
||||||
* characters are present after a non-overflowing parsed number, the
|
|
||||||
* function will return -EINVAL, and *@v will be set to 0.
|
|
||||||
*/
|
*/
|
||||||
int parse_uint_full(const char *s, int base, uint64_t *value)
|
int parse_uint_full(const char *s, int base, uint64_t *value)
|
||||||
{
|
{
|
||||||
const char *endp;
|
return parse_uint(s, NULL, base, value);
|
||||||
int r;
|
|
||||||
|
|
||||||
r = parse_uint(s, &endp, base, value);
|
|
||||||
if (r < 0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (*endp) {
|
|
||||||
*value = 0;
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qemu_parse_fd(const char *param)
|
int qemu_parse_fd(const char *param)
|
||||||
|
|
Loading…
Reference in New Issue