Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ebblake committed Jun 1, 2023
1 parent 26be416 commit cf82e72
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 24 deletions.
18 changes: 16 additions & 2 deletions tests/unit/test-cutils.c
Expand Up @@ -270,14 +270,26 @@ static void test_parse_uint_full_correct(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;
const char *str = "-2junk";
int r;

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);
}

Expand Down Expand Up @@ -3328,6 +3340,8 @@ int main(int argc, char **argv)
test_parse_uint_full_correct);
g_test_add_func("/cutils/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 */
g_test_add_func("/cutils/qemu_strtoi/correct",
Expand Down
34 changes: 12 additions & 22 deletions util/cutils.c
Expand Up @@ -722,8 +722,7 @@ const char *qemu_strchrnul(const char *s, int c)
* parse_uint:
*
* @s: String to parse
* @endptr: Destination for pointer to first character not consumed, must
* not be %NULL
* @endptr: Destination for pointer to first character not consumed
* @base: integer base, between 2 and 36 inclusive, or 0
* @value: Destination for parsed integer value
*
Expand All @@ -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
* 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 you want to allow negative numbers that wrap around within
Expand Down Expand Up @@ -784,7 +784,12 @@ int parse_uint(const char *s, const char **endptr, int base, uint64_t *value)

out:
*value = val;
*endptr = endp;
if (endptr) {
*endptr = endp;
} else if (s && *endp) {
r = -EINVAL;
*value = 0;
}
return r;
}

Expand All @@ -795,28 +800,13 @@ int parse_uint(const char *s, const char **endptr, int base, uint64_t *value)
* @base: integer base, between 2 and 36 inclusive, or 0
* @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
* 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.
* Shorthand for parse_uint(s, NULL, base, value).
*/
int parse_uint_full(const char *s, int base, uint64_t *value)
{
const char *endp;
int r;

r = parse_uint(s, &endp, base, value);
if (r < 0) {
return r;
}
if (*endp) {
*value = 0;
return -EINVAL;
}

return 0;
return parse_uint(s, NULL, base, value);
}

int qemu_parse_fd(const char *param)
Expand Down

0 comments on commit cf82e72

Please sign in to comment.