2013-02-04 19:27:45 +01:00
|
|
|
/*
|
|
|
|
* cutils.c unit-tests
|
|
|
|
*
|
2023-05-12 04:10:15 +02:00
|
|
|
* Copyright Red Hat
|
2013-02-04 19:27:45 +01:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Eduardo Habkost <ehabkost@redhat.com>
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
#include <math.h>
|
|
|
|
|
2016-02-08 19:08:51 +01:00
|
|
|
#include "qemu/osdep.h"
|
2016-03-20 18:16:19 +01:00
|
|
|
#include "qemu/cutils.h"
|
2018-06-25 14:41:57 +02:00
|
|
|
#include "qemu/units.h"
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
static void test_parse_uint_null(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(NULL, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -EINVAL);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_empty(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -EINVAL);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_whitespace(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = " \t ";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -EINVAL);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_parse_uint_invalid(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = " \t xxx";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -EINVAL);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_parse_uint_trailing(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "123xxx";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_correct(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "123";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_octal(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "0123";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_decimal(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "0123";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 10, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_llong_max(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
2013-02-04 19:27:45 +01:00
|
|
|
char *str = g_strdup_printf("%llu", (unsigned long long)LLONG_MAX + 1);
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, (unsigned long long)LLONG_MAX + 1);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_parse_uint_max(void)
|
2013-02-04 19:27:45 +01:00
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
char *str = g_strdup_printf("%llu", ULLONG_MAX);
|
2013-02-04 19:27:45 +01:00
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(r, ==, 0);
|
|
|
|
g_assert_cmpuint(i, ==, ULLONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_overflow(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i;
|
|
|
|
const char *endptr;
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
i = 999;
|
2023-05-22 21:04:29 +02:00
|
|
|
endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "99999999999999999999999999999999999999";
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(i, ==, ULLONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
i = 999;
|
2023-05-22 21:04:29 +02:00
|
|
|
endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(i, ==, ULLONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
i = 999;
|
2023-05-22 21:04:29 +02:00
|
|
|
endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, ULLONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_negative(void)
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i;
|
|
|
|
const char *endptr;
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
i = 999;
|
2023-05-22 21:04:29 +02:00
|
|
|
endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = " \t -321";
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(i, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
i = 999;
|
2023-05-22 21:04:29 +02:00
|
|
|
endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-0xffffffff00000001";
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(i, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_negzero(void)
|
2013-02-04 19:27:45 +01:00
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
|
|
|
const char *endptr = "somewhere";
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str = " -0";
|
2013-02-04 19:27:45 +01:00
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint(str, &endptr, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -ERANGE);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_full_trailing(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "123xxx";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint_full(str, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, -EINVAL);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_parse_uint_full_correct(void)
|
|
|
|
{
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
2013-02-04 19:27:45 +01:00
|
|
|
const char *str = "123";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint_full(str, 0, &i);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(r, ==, 0);
|
2023-05-12 04:10:16 +02:00
|
|
|
g_assert_cmpuint(i, ==, 123);
|
2013-02-04 19:27:45 +01:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_parse_uint_full_erange_junk(void)
|
|
|
|
{
|
2023-05-22 21:04:30 +02:00
|
|
|
/* EINVAL has priority over ERANGE */
|
2023-05-22 21:04:29 +02:00
|
|
|
uint64_t i = 999;
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str = "-2junk";
|
|
|
|
int r;
|
|
|
|
|
2023-05-22 21:04:29 +02:00
|
|
|
r = parse_uint_full(str, 0, &i);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
|
2023-05-22 21:04:30 +02:00
|
|
|
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);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(i, ==, 0);
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoi_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_whitespace(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_invalid(void)
|
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_octal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 8, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_decimal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 10, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_hex(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoi(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_max(void)
|
|
|
|
{
|
|
|
|
char *str = g_strdup_printf("%d", INT_MAX);
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_overflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int res;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "2147483648"; /* INT_MAX + 1ll */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x7fffffffffffffff"; /* LLONG_MAX */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x8000000000000000"; /* (uint64_t)LLONG_MIN */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x18000000080000000"; /* 65 bits, 32-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi_min(void)
|
2017-12-22 13:46:23 +01:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
char *str = g_strdup_printf("%d", INT_MIN);
|
2017-12-22 13:46:23 +01:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
2017-12-22 13:46:23 +01:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi_underflow(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int res;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
str = "-2147483649"; /* INT_MIN - 1ll */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x7fffffffffffffff"; /* -LLONG_MAX */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x8000000000000000"; /* (uint64_t)LLONG_MIN */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x18000000080000000"; /* 65 bits, 32-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoi_negative(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int res;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
str = " \t -321";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-2147483648"; /* INT_MIN */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
2017-12-22 13:46:23 +01:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_full_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "123";
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_full_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_full_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
2023-05-12 04:10:16 +02:00
|
|
|
int res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_full_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoi_full_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
int res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 123);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi_full_max(void)
|
|
|
|
{
|
|
|
|
char *str = g_strdup_printf("%d", INT_MAX);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
int res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, INT_MAX);
|
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-9999999999junk";
|
|
|
|
int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpint(res, ==, INT_MIN);
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoui_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_whitespace(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_invalid(void)
|
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_octal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 8, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_decimal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 10, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_hex(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoui(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoui_wrap(void)
|
|
|
|
{
|
2023-05-22 21:04:27 +02:00
|
|
|
/* wraparound is consistent with 32-bit strtoul */
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str = "-4294967295"; /* 1 mod 2^32 */
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
2023-05-22 21:04:27 +02:00
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 1);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoui_max(void)
|
|
|
|
{
|
|
|
|
char *str = g_strdup_printf("%u", UINT_MAX);
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, UINT_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_overflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
unsigned int res;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "4294967296"; /* UINT_MAX + 1ll */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x7fffffffffffffff"; /* LLONG_MAX */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x8000000000000000"; /* (uint64_t)LLONG_MIN */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0xffffffff00000001"; /* ULLONG_MAX - UINT_MAX + 1 (not 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0xfffffffffffffffe"; /* ULLONG_MAX - 1 (not UINT_MAX - 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
2023-05-22 21:04:27 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x18000000080000000"; /* 65 bits, 32-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_underflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
unsigned int res;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-4294967296"; /* -(long long)UINT_MAX - 1ll */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-18446744073709551615"; /* -UINT64_MAX (not -(-1)) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
2023-05-22 21:04:27 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-0xffffffff00000002";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
2023-05-22 21:04:27 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, 32-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x18000000080000000"; /* 65 bits, 32-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, (unsigned int)-321);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoui_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoui_full_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "123";
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 123);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_full_null(void)
|
|
|
|
{
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(NULL, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_full_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoui_full_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, (unsigned int)-321);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoui_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
static void test_qemu_strtoui_full_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
unsigned int res = 999;
|
2017-12-22 13:46:23 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2017-12-22 13:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoui_full_max(void)
|
|
|
|
{
|
|
|
|
char *str = g_strdup_printf("%u", UINT_MAX);
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, UINT_MAX);
|
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoui_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-9999999999junk";
|
|
|
|
unsigned int res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoui(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpuint(res, ==, UINT_MAX);
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:17 +02:00
|
|
|
static void test_qemu_strtol_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_whitespace(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_invalid(void)
|
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_octal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 8, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_decimal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 10, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_hex(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtol(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_max(void)
|
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%ld", LONG_MAX);
|
2015-07-20 01:02:17 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_overflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
long res;
|
2015-07-20 01:02:17 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
/* 1 more than LONG_MAX */
|
|
|
|
str = LONG_MAX == INT_MAX ? "2147483648" : "9223372036854775808";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2015-07-20 01:02:17 +02:00
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
if (LONG_MAX == INT_MAX) {
|
|
|
|
str = "0xffffffff00000001"; /* ULLONG_MAX - UINT_MAX + 1 (not 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, either sign bit position clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x18000000080000000"; /* 65 bits, either sign bit position set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtol_min(void)
|
2015-07-20 01:02:17 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
char *str = g_strdup_printf("%ld", LONG_MIN);
|
2015-07-20 01:02:17 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
2015-07-20 01:02:17 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_underflow(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
long res;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* 1 less than LONG_MIN */
|
|
|
|
str = LONG_MIN == INT_MIN ? "-2147483649" : "-9223372036854775809";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
if (LONG_MAX == INT_MAX) {
|
|
|
|
str = "-18446744073709551615"; /* -UINT64_MAX (not 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, either sign bit position clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x18000000080000000"; /* 65 bits, either sign bit position set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtol_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_negzero(void)
|
2015-07-20 01:02:17 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str = " -0";
|
2015-07-20 01:02:17 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_full_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "123";
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_full_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_full_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
long res = 999L;
|
|
|
|
int err;
|
|
|
|
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
2015-07-20 01:02:17 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_full_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtol_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:17 +02:00
|
|
|
static void test_qemu_strtol_full_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
long res = 999;
|
2015-07-20 01:02:17 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 123);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtol_full_max(void)
|
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%ld", LONG_MAX);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
long res = 999;
|
2015-07-20 01:02:17 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MAX);
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:17 +02:00
|
|
|
}
|
2015-07-20 01:02:18 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtol_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-99999999999999999999junk";
|
|
|
|
long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtol(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpint(res, ==, LONG_MIN);
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
static void test_qemu_strtoul_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_null(void)
|
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(NULL, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_whitespace(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_invalid(void)
|
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_octal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 8, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_decimal(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 10, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_hex(void)
|
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
res = 999;
|
|
|
|
endptr = &f;
|
|
|
|
err = qemu_strtoul(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoul_wrap(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* 1 mod 2^(sizeof(long)*8) */
|
|
|
|
str = LONG_MAX == INT_MAX ? "-4294967295" : "-18446744073709551615";
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 1);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
static void test_qemu_strtoul_max(void)
|
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%lu", ULONG_MAX);
|
2015-07-20 01:02:18 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, ULONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_overflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
unsigned long res;
|
2015-07-20 01:02:18 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
/* 1 more than ULONG_MAX */
|
|
|
|
str = ULONG_MAX == UINT_MAX ? "4294967296" : "18446744073709551616";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
if (LONG_MAX == INT_MAX) {
|
|
|
|
str = "0xffffffff00000001"; /* UINT64_MAX - UINT_MAX + 1 (not 1) */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, either sign bit position clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2015-07-20 01:02:18 +02:00
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x18000000080000000"; /* 65 bits, either sign bit position set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_underflow(void)
|
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
unsigned long res;
|
2015-07-20 01:02:18 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
/* 1 less than -ULONG_MAX */
|
|
|
|
str = ULONG_MAX == UINT_MAX ? "-4294967296" : "-18446744073709551616";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
if (LONG_MAX == INT_MAX) {
|
|
|
|
str = "-0xffffffff00000002";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, either sign bit position clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-0x18000000080000000"; /* 65 bits, either sign bit position set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, -321ul);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoul_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
static void test_qemu_strtoul_full_correct(void)
|
|
|
|
{
|
|
|
|
const char *str = "123";
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_full_null(void)
|
|
|
|
{
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(NULL, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_full_empty(void)
|
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
static void test_qemu_strtoul_full_negative(void)
|
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, -321ul);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoul_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
static void test_qemu_strtoul_full_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
unsigned long res = 999;
|
2015-07-20 01:02:18 +02:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoul_full_max(void)
|
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%lu", ULONG_MAX);
|
2015-07-20 01:02:18 +02:00
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, ULONG_MAX);
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:18 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoul_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-99999999999999999999junk";
|
|
|
|
unsigned long res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoul(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpuint(res, ==, ULONG_MAX);
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_correct(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_null(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(NULL, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_empty(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_whitespace(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_invalid(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_trailing(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_octal(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 8, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_decimal(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 10, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_hex(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 16, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_max(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%lld", LLONG_MAX);
|
2015-07-20 01:02:19 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, LLONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_overflow(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int64_t res;
|
2015-07-20 01:02:19 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "9223372036854775808"; /* 1 more than INT64_MAX */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(res, ==, INT64_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi64_min(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
char *str = g_strdup_printf("%lld", LLONG_MIN);
|
2015-07-20 01:02:19 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, 0);
|
2015-07-20 01:02:19 +02:00
|
|
|
g_assert_cmpint(res, ==, LLONG_MIN);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtoi64_underflow(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int64_t res;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
str = "-9223372036854775809"; /* 1 less than INT64_MIN */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x18000000080000000"; /* 65 bits, 64-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MIN);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_negative(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi64_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi64(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_correct(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "123";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 123);
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_null(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(NULL, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_empty(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 0);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_negative(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, -321);
|
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi64_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_trailing(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpint(res, ==, 123);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtoi64_full_max(void)
|
2015-07-20 01:02:19 +02:00
|
|
|
{
|
|
|
|
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%lld", LLONG_MAX);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
int64_t res = 999;
|
2015-07-20 01:02:19 +02:00
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
2015-07-20 01:02:19 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpint(res, ==, LLONG_MAX);
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:19 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtoi64_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-99999999999999999999junk";
|
|
|
|
int64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtoi64(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpint(res, ==, INT64_MIN);
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_correct(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "12345 foo";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 12345);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 5);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_null(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(NULL, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_null(endptr);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_empty(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_whitespace(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t ";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_invalid(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = " xxxx \t abc";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_trailing(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "123xxx";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 3);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_octal(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 8, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 0123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_decimal(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 10, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
str = "123";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_hex(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "0123";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 16, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
str = "0x123";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, 0x123);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2021-03-23 17:53:00 +01:00
|
|
|
|
|
|
|
str = "0x";
|
|
|
|
endptr = &f;
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtou64(str, &endptr, 16, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmphex(res, ==, 0);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + 1);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtou64_wrap(void)
|
|
|
|
{
|
|
|
|
const char *str = "-18446744073709551615"; /* 1 mod 2^64 */
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 1);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_max(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%llu", ULLONG_MAX);
|
2015-07-20 01:02:20 +02:00
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, ULLONG_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_overflow(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
uint64_t res;
|
2015-07-20 01:02:20 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "18446744073709551616"; /* 1 more than UINT64_MAX */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "0x18000000080000000"; /* 65 bits, 64-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_underflow(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
uint64_t res;
|
2015-07-20 01:02:20 +02:00
|
|
|
int err;
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-99999999999999999999999999999999999999999999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
|
|
|
|
str = "-0x10000000000000000"; /* 65 bits, 64-bit sign bit clear */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
2023-05-12 04:10:16 +02:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
str = "-0x18000000080000000"; /* 65 bits, 64-bit sign bit set */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_negative(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, -321ull);
|
2023-05-12 04:10:15 +02:00
|
|
|
g_assert_true(endptr == str + strlen(str));
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtou64_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
char f = 'X';
|
|
|
|
const char *endptr = &f;
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtou64(str, &endptr, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
g_assert_true(endptr == str + strlen(str));
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_correct(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "18446744073709551614";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, 18446744073709551614ull);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_null(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(NULL, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:38 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_empty(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
2015-09-10 10:02:00 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 0);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_negative(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = " \t -321";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmpuint(res, ==, -321ull);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtou64_full_negzero(void)
|
|
|
|
{
|
|
|
|
const char *str = " -0";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpuint(res, ==, 0);
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_trailing(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
|
|
|
const char *str = "18446744073709551614xxxxxx";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
test-cutils: Test integral qemu_strto* value on failures
We are inconsistent on the contents of *value after a strto* parse
failure. I found the following behaviors:
- parse_uint() and parse_uint_full(), which document that *value is
slammed to 0 on all EINVAL failures and 0 or UINT_MAX on ERANGE
failures, and has unit tests for that (note that parse_uint requires
non-NULL endptr, and does not fail with EINVAL for trailing junk)
- qemu_strtosz(), which leaves *value untouched on all failures (both
EINVAL and ERANGE), and has unit tests but not documentation for
that
- qemu_strtoi() and other integral friends, which document *value on
ERANGE failures but is unspecified on EINVAL (other than implicitly
by comparison to libc strto*); there, *value is untouched for NULL
string, slammed to 0 on no conversion, and left at the prefix value
on NULL endptr; unit tests do not consistently check the value
- qemu_strtod(), which documents *value on ERANGE failures but is
unspecified on EINVAL; there, *value is untouched for NULL string,
slammed to 0.0 for no conversion, and left at the prefix value on
NULL endptr; there are no unit tests (other than indirectly through
qemu_strtosz)
- qemu_strtod_finite(), which documents *value on ERANGE failures but
is unspecified on EINVAL; there, *value is left at the prefix for
'inf' or 'nan' and untouched in all other cases; there are no unit
tests (other than indirectly through qemu_strtosz)
Upcoming patches will change behaviors for consistency, but it's best
to first have more unit test coverage to see the impact of those
changes.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-4-eblake@redhat.com>
2023-05-22 21:04:25 +02:00
|
|
|
g_assert_cmpuint(res, ==, 18446744073709551614ULL);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
static void test_qemu_strtou64_full_max(void)
|
2015-07-20 01:02:20 +02:00
|
|
|
{
|
2016-07-07 20:43:40 +02:00
|
|
|
char *str = g_strdup_printf("%lld", ULLONG_MAX);
|
2015-07-20 01:02:20 +02:00
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
2017-02-21 21:13:48 +01:00
|
|
|
g_assert_cmphex(res, ==, ULLONG_MAX);
|
2016-07-07 20:43:40 +02:00
|
|
|
g_free(str);
|
2015-07-20 01:02:20 +02:00
|
|
|
}
|
|
|
|
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
static void test_qemu_strtou64_full_erange_junk(void)
|
|
|
|
{
|
|
|
|
/* EINVAL has priority over ERANGE */
|
|
|
|
const char *str = "-99999999999999999999junk";
|
|
|
|
uint64_t res = 999;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = qemu_strtou64(str, NULL, 0, &res);
|
|
|
|
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpuint(res, ==, UINT64_MAX);
|
|
|
|
}
|
|
|
|
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
static void test_qemu_strtod_simple(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* no radix or exponent */
|
|
|
|
str = "1";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
g_assert_true(endptr == str + 1);
|
|
|
|
|
|
|
|
/* leading space and sign */
|
|
|
|
str = " -0.0";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, -0.0);
|
|
|
|
g_assert_true(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 5);
|
|
|
|
|
|
|
|
/* fraction only */
|
|
|
|
str = "+.5";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
|
|
|
g_assert_true(endptr == str + 3);
|
|
|
|
|
|
|
|
/* exponent */
|
|
|
|
str = "1.e+1";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 10.0);
|
|
|
|
g_assert_true(endptr == str + 5);
|
|
|
|
|
|
|
|
/* hex without radix */
|
|
|
|
str = "0x10";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 16.0);
|
|
|
|
g_assert_true(endptr == str + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_einval(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* empty */
|
|
|
|
str = "";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str);
|
|
|
|
|
|
|
|
/* NULL */
|
|
|
|
str = NULL;
|
|
|
|
endptr = "random";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_null(endptr);
|
|
|
|
|
|
|
|
/* not recognizable */
|
|
|
|
str = " junk";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_erange(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* overflow */
|
|
|
|
str = "9e999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, ==, HUGE_VAL);
|
|
|
|
g_assert_true(endptr == str + 5);
|
|
|
|
|
|
|
|
str = "-9e+999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, ==, -HUGE_VAL);
|
|
|
|
g_assert_true(endptr == str + 7);
|
|
|
|
|
|
|
|
/* underflow */
|
|
|
|
str = "-9e-999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, >=, -DBL_MIN);
|
|
|
|
g_assert_cmpfloat(res, <=, -0.0);
|
|
|
|
g_assert_true(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_nonfinite(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* infinity */
|
|
|
|
str = "inf";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_true(isinf(res));
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 3);
|
|
|
|
|
|
|
|
str = "-infinity";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_true(isinf(res));
|
|
|
|
g_assert_true(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 9);
|
|
|
|
|
|
|
|
/* not a number */
|
|
|
|
str = " NaN";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_true(isnan(res));
|
|
|
|
g_assert_true(endptr == str + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* trailing whitespace */
|
|
|
|
str = "1. ";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
g_assert_true(endptr == str + 2);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
|
|
|
|
/* trailing e is not an exponent */
|
|
|
|
str = ".5e";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
|
|
|
g_assert_true(endptr == str + 2);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
|
|
|
|
|
|
|
/* trailing ( not part of long NaN */
|
|
|
|
str = "nan(";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_true(isnan(res));
|
|
|
|
g_assert_true(endptr == str + 3);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_true(isnan(res));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_erange_junk(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* ERANGE with trailing junk... */
|
|
|
|
str = "1e-999junk";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, <=, DBL_MIN);
|
|
|
|
g_assert_cmpfloat(res, >=, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 6);
|
|
|
|
|
|
|
|
/* ...has less priority than EINVAL when full parse not possible */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_simple(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* no radix or exponent */
|
|
|
|
str = "1";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
g_assert_true(endptr == str + 1);
|
|
|
|
|
|
|
|
/* leading space and sign */
|
|
|
|
str = " -0.0";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, -0.0);
|
|
|
|
g_assert_true(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 5);
|
|
|
|
|
|
|
|
/* fraction only */
|
|
|
|
str = "+.5";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
|
|
|
g_assert_true(endptr == str + 3);
|
|
|
|
|
|
|
|
/* exponent */
|
|
|
|
str = "1.e+1";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 10.0);
|
|
|
|
g_assert_true(endptr == str + 5);
|
|
|
|
|
|
|
|
/* hex without radix */
|
|
|
|
str = "0x10";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 16.0);
|
|
|
|
g_assert_true(endptr == str + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_einval(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* empty */
|
|
|
|
str = "";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
|
|
|
|
/* NULL */
|
|
|
|
str = NULL;
|
|
|
|
endptr = "random";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_null(endptr);
|
|
|
|
|
|
|
|
/* not recognizable */
|
|
|
|
str = " junk";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_erange(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
2023-05-22 21:04:40 +02:00
|
|
|
/* overflow turns into EINVAL */
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
str = "9e999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str);
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
|
|
|
|
str = "-9e+999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str);
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
|
2023-05-22 21:04:40 +02:00
|
|
|
/* underflow is still possible */
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
str = "-9e-999";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, >=, -DBL_MIN);
|
|
|
|
g_assert_cmpfloat(res, <=, -0.0);
|
|
|
|
g_assert_true(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_nonfinite(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* infinity */
|
|
|
|
str = "inf";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
|
|
|
|
str = "-infinity";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
|
|
|
|
/* not a number */
|
|
|
|
str = " NaN";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_trailing(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* trailing whitespace */
|
|
|
|
str = "1. ";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
g_assert_true(endptr == str + 2);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 1.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
|
|
|
|
/* trailing e is not an exponent */
|
|
|
|
str = ".5e";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, 0);
|
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
|
|
|
g_assert_true(endptr == str + 2);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.5);
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
|
|
|
|
/* trailing ( not part of long NaN */
|
|
|
|
str = "nan(";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
g_assert_true(endptr == str);
|
|
|
|
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtod_finite_erange_junk(void)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
const char *endptr;
|
|
|
|
int err;
|
|
|
|
double res;
|
|
|
|
|
|
|
|
/* ERANGE with trailing junk... */
|
|
|
|
str = "1e-999junk";
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, &endptr, &res);
|
|
|
|
g_assert_cmpint(err, ==, -ERANGE);
|
|
|
|
g_assert_cmpfloat(res, <=, DBL_MIN);
|
|
|
|
g_assert_cmpfloat(res, >=, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
|
|
|
g_assert_true(endptr == str + 6);
|
|
|
|
|
|
|
|
/* ...has less priority than EINVAL when full parse not possible */
|
|
|
|
endptr = "somewhere";
|
|
|
|
res = 999;
|
|
|
|
err = qemu_strtod_finite(str, NULL, &res);
|
|
|
|
g_assert_cmpint(err, ==, -EINVAL);
|
2023-05-22 21:04:40 +02:00
|
|
|
g_assert_cmpfloat(res, ==, 0.0);
|
|
|
|
g_assert_false(signbit(res));
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
}
|
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
typedef int (*qemu_strtosz_fn)(const char *, const char **, uint64_t *);
|
|
|
|
static void do_strtosz_full(const char *str, qemu_strtosz_fn fn,
|
|
|
|
int exp_ptr_ret, uint64_t exp_ptr_val,
|
|
|
|
size_t exp_ptr_offset, int exp_null_ret,
|
|
|
|
uint64_t exp_null_val)
|
2015-09-16 18:02:57 +02:00
|
|
|
{
|
2023-05-22 21:04:33 +02:00
|
|
|
const char *endptr = "somewhere";
|
|
|
|
uint64_t val = 0xbaadf00d;
|
|
|
|
int ret;
|
2015-09-16 18:02:57 +02:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
ret = fn(str, &endptr, &val);
|
|
|
|
g_assert_cmpint(ret, ==, exp_ptr_ret);
|
|
|
|
g_assert_cmpuint(val, ==, exp_ptr_val);
|
2023-05-22 21:04:34 +02:00
|
|
|
if (str) {
|
|
|
|
g_assert_true(endptr == str + exp_ptr_offset);
|
|
|
|
} else {
|
|
|
|
g_assert_cmpint(exp_ptr_offset, ==, 0);
|
|
|
|
g_assert_null(endptr);
|
|
|
|
}
|
2023-05-22 21:04:33 +02:00
|
|
|
|
|
|
|
val = 0xbaadf00d;
|
|
|
|
ret = fn(str, NULL, &val);
|
|
|
|
g_assert_cmpint(ret, ==, exp_null_ret);
|
|
|
|
g_assert_cmpuint(val, ==, exp_null_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_strtosz(const char *str, int exp_ret, uint64_t exp_val,
|
|
|
|
size_t exp_offset)
|
|
|
|
{
|
|
|
|
do_strtosz_full(str, qemu_strtosz, exp_ret, exp_val, exp_offset,
|
|
|
|
exp_ret, exp_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_strtosz_MiB(const char *str, int exp_ret, uint64_t exp_val,
|
|
|
|
size_t exp_offset)
|
|
|
|
{
|
|
|
|
do_strtosz_full(str, qemu_strtosz_MiB, exp_ret, exp_val, exp_offset,
|
|
|
|
exp_ret, exp_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_strtosz_metric(const char *str, int exp_ret, uint64_t exp_val,
|
|
|
|
size_t exp_offset)
|
|
|
|
{
|
|
|
|
do_strtosz_full(str, qemu_strtosz_metric, exp_ret, exp_val, exp_offset,
|
|
|
|
exp_ret, exp_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtosz_simple(void)
|
|
|
|
{
|
|
|
|
do_strtosz("0", 0, 0, 1);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2021-02-11 21:44:35 +01:00
|
|
|
/* Leading 0 gives decimal results, not octal */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("08", 0, 8, 2);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Leading space and + are ignored */
|
|
|
|
do_strtosz(" +12345", 0, 12345, 7);
|
2015-09-16 18:02:57 +02:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 2^53-1 */
|
|
|
|
do_strtosz("9007199254740991", 0, 0x1fffffffffffffULL, 16);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 2^53 */
|
|
|
|
do_strtosz("9007199254740992", 0, 0x20000000000000ULL, 16);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 2^53+1 */
|
|
|
|
do_strtosz("9007199254740993", 0, 0x20000000000001ULL, 16);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 0xfffffffffffff800 (53 msbs set) */
|
|
|
|
do_strtosz("18446744073709549568", 0, 0xfffffffffffff800ULL, 20);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 0xfffffffffffffbff */
|
|
|
|
do_strtosz("18446744073709550591", 0, 0xfffffffffffffbffULL, 20);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 0xffffffffffffffff */
|
|
|
|
do_strtosz("18446744073709551615", 0, 0xffffffffffffffffULL, 20);
|
2021-02-11 21:44:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtosz_hex(void)
|
|
|
|
{
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("0x0", 0, 0, 3);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("0xab", 0, 171, 4);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz(" +0xae", 0, 174, 6);
|
2015-09-16 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtosz_units(void)
|
|
|
|
{
|
2023-05-22 21:04:36 +02:00
|
|
|
/* default scale depends on function */
|
|
|
|
do_strtosz("1", 0, 1, 1);
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz_MiB("1", 0, MiB, 1);
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz_metric("1", 0, 1, 1);
|
2015-09-16 18:02:57 +02:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Explicit byte suffix works for all functions */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("1B", 0, 1, 2);
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz_MiB("1B", 0, 1, 2);
|
|
|
|
do_strtosz_metric("1B", 0, 1, 2);
|
2015-09-16 18:02:57 +02:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Expose the scale */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("1K", 0, KiB, 2);
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz_MiB("1K", 0, KiB, 2);
|
|
|
|
do_strtosz_metric("1K", 0, 1000, 2);
|
|
|
|
|
|
|
|
/* Other suffixes, see also test_qemu_strtosz_metric */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("1M", 0, MiB, 2);
|
|
|
|
do_strtosz("1G", 0, GiB, 2);
|
|
|
|
do_strtosz("1T", 0, TiB, 2);
|
|
|
|
do_strtosz("1P", 0, PiB, 2);
|
|
|
|
do_strtosz("1E", 0, EiB, 2);
|
2015-09-16 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_qemu_strtosz_float(void)
|
|
|
|
{
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("0.5E", 0, EiB / 2, 4);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Implied M suffix okay */
|
|
|
|
do_strtosz_MiB("0.5", 0, MiB / 2, 3);
|
|
|
|
|
2021-02-11 21:44:35 +01:00
|
|
|
/* For convenience, a fraction of 0 is tolerated even on bytes */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("1.0B", 0, 1, 4);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* An empty fraction tail is tolerated */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("1.k", 0, 1024, 3);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* An empty fraction head is tolerated */
|
|
|
|
do_strtosz(" .5k", 0, 512, 4);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2021-02-11 21:44:35 +01:00
|
|
|
/* For convenience, we permit values that are not byte-exact */
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz("12.345M", 0, (uint64_t) (12.345 * MiB + 0.5), 7);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* Fraction tail can round up */
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz("1.9999k", 0, 2048, 7);
|
|
|
|
do_strtosz("1.9999999999999999999999999999999999999999999999999999k", 0,
|
2023-05-22 21:04:41 +02:00
|
|
|
2048, 55);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* ERANGE underflow in the fraction tail does not matter for 'k' */
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz("1."
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
2023-05-22 21:04:41 +02:00
|
|
|
"1k", 0, 1024, 354);
|
2015-09-16 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:55 +01:00
|
|
|
static void test_qemu_strtosz_invalid(void)
|
|
|
|
{
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz(NULL, -EINVAL, 0, 0);
|
2023-05-22 21:04:34 +02:00
|
|
|
|
|
|
|
/* Must parse at least one digit */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("", -EINVAL, 0, 0);
|
|
|
|
do_strtosz(" \t ", -EINVAL, 0, 0);
|
|
|
|
do_strtosz(".", -EINVAL, 0, 0);
|
|
|
|
do_strtosz(" .", -EINVAL, 0, 0);
|
|
|
|
do_strtosz(" .k", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("inf", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("NaN", -EINVAL, 0, 0);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Lone suffix is not okay */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("k", -EINVAL, 0, 0);
|
|
|
|
do_strtosz(" M", -EINVAL, 0, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2021-02-11 21:44:35 +01:00
|
|
|
/* Fractional values require scale larger than bytes */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("1.1B", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("1.1", -EINVAL, 0, 0);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* 'B' cannot have any nonzero fraction, even with rounding or underflow */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("1.00001B", -EINVAL, 0, 0);
|
2023-05-22 21:04:41 +02:00
|
|
|
do_strtosz("1.00000000000000000001B", -EINVAL, 0, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz("1."
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
2023-05-22 21:04:41 +02:00
|
|
|
"1B", -EINVAL, 0, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
utils: Improve qemu_strtosz() to have 64 bits of precision
We have multiple clients of qemu_strtosz (qemu-io, the opts visitor,
the keyval visitor), and it gets annoying that edge-case testing is
impacted by implicit rounding to 53 bits of precision due to parsing
with strtod(). As an example posted by Rich Jones:
$ nbdkit memory $(( 2**63 - 2**30 )) --run \
'build/qemu-io -f raw "$uri" -c "w -P 3 $(( 2**63 - 2**30 - 512 )) 512" '
write failed: Input/output error
because 9223372035781033472 got rounded to 0x7fffffffc0000000 which is
out of bounds.
It is also worth noting that our existing parser, by virtue of using
strtod(), accepts decimal AND hex numbers, even though test-cutils
previously lacked any coverage of the latter until the previous patch.
We do have existing clients that expect a hex parse to work (for
example, iotest 33 using qemu-io -c "write -P 0xa 0x200 0x400"), but
strtod() parses "08" as 8 rather than as an invalid octal number, so
we know there are no clients that depend on octal. Our use of
strtod() also means that "0x1.8k" would actually parse as 1536 (the
fraction is 8/16), rather than 1843 (if the fraction were 8/10); but
as this was not covered in the testsuite, I have no qualms forbidding
hex fractions as invalid, so this patch declares that the use of
fractions is only supported with decimal input, and enhances the
testsuite to document that.
Our previous use of strtod() meant that -1 parsed as a negative; now
that we parse with strtoull(), negative values can wrap around modulo
2^64, so we have to explicitly check whether the user passed in a '-';
and make it consistent to also reject '-0'. This has the minor effect
of treating negative values as EINVAL (with no change to endptr)
rather than ERANGE (with endptr advanced to what was parsed), visible
in the updated iotest output.
We also had no testsuite coverage of "1.1e0k", which happened to parse
under strtod() but is unlikely to occur in practice; as long as we are
making things more robust, it is easy enough to reject the use of
exponents in a strtod parse.
The fix is done by breaking the parse into an integer prefix (no loss
in precision), rejecting negative values (since we can no longer rely
on strtod() to do that), determining if a decimal or hexadecimal parse
was intended (with the new restriction that a fractional hex parse is
not allowed), and where appropriate, using a floating point fractional
parse (where we also scan to reject use of exponents in the fraction).
The bulk of the patch is then updates to the testsuite to match our
new precision, as well as adding new cases we reject (whether they
were rejected or inadvertently accepted before).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20210211204438.1184395-3-eblake@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2021-02-11 21:44:36 +01:00
|
|
|
/* No hex fractions */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("0x1.8k", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("0x1.k", -EINVAL, 0, 0);
|
2022-12-16 10:50:05 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* No hex suffixes */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("0x18M", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("0x1p1", -EINVAL, 0, 0);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* decimal in place of scaling suffix */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("1.1.k", -EINVAL, 0, 0);
|
|
|
|
do_strtosz("1.1.", -EINVAL, 0, 0);
|
2017-02-21 21:13:55 +01:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:56 +01:00
|
|
|
static void test_qemu_strtosz_trailing(void)
|
|
|
|
{
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Trailing whitespace */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("1k ", qemu_strtosz, 0, 1024, 2, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Unknown suffix overrides even implied scale*/
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("123xxx", qemu_strtosz, 0, 123, 3, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Implied scale allows partial parse */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("123xxx", qemu_strtosz_MiB, 0, 123 * MiB, 3, -EINVAL, 0);
|
|
|
|
do_strtosz_full("1.5.k", qemu_strtosz_MiB, 0, 1.5 * MiB, 3, -EINVAL, 0);
|
2021-02-11 21:44:35 +01:00
|
|
|
|
2023-05-22 21:04:36 +02:00
|
|
|
/* Junk after one-byte suffix */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("1kiB", qemu_strtosz, 0, 1024, 2, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Incomplete hex is an unknown suffix */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("0x", qemu_strtosz, 0, 0, 1, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Hex literals use only one leading zero */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("00x1", qemu_strtosz, 0, 0, 2, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* No support for binary literals; 'b' is valid suffix */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("0b1000", qemu_strtosz, 0, 0, 2, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Junk after decimal */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("0.NaN", qemu_strtosz, 0, 0, 2, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Although negatives are invalid, '-' may be in trailing junk */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("123-45", qemu_strtosz, 0, 123, 3, -EINVAL, 0);
|
|
|
|
do_strtosz_full(" 123 - 45", qemu_strtosz, 0, 123, 4, -EINVAL, 0);
|
test-cutils: Prepare for upcoming semantic change in qemu_strtosz
A quick search for 'qemu_strtosz' in the code base shows that outside
of the testsuite, the ONLY place that passes a non-NULL pointer to
@endptr of any variant of a size parser is in hmp.c (the 'o' parser of
monitor_parse_arguments), and that particular caller warns of
"extraneous characters at the end of line" unless the trailing bytes
are purely whitespace. Thus, it makes no semantic difference at the
high level whether we parse "1.5e1k" as "1" + ".5e1" + "k" (an attempt
to use scientific notation in strtod with a scaling suffix of 'k' with
no trailing junk, but which qemu_strtosz says should fail with
EINVAL), or as "1.5e" + "1k" (a valid size with scaling suffix of 'e'
for exabytes, followed by two junk bytes) - either way, any user
passing such a string will get an error message about a parse failure.
However, an upcoming patch to qemu_strtosz will fix other corner case
bugs in handling the fractional portion of a size, and in doing so, it
is easier to declare that qemu_strtosz() itself stops parsing at the
first 'e' rather than blindly consuming whatever strtod() will
recognize. Once that is fixed, the difference will be visible at the
low level (getting a valid parse with trailing garbage when @endptr is
non-NULL, while continuing to get -EINVAL when @endptr is NULL); this
is easier to demonstrate by moving the affected strings from
test_qemu_strtosz_invalid() (which declares them as always -EINVAL) to
test_qemu_strtosz_trailing() (where @endptr affects behavior, for now
with FIXME comments).
Note that a similar argument could be made for having "0x1.5" or
"0x1M" parse as 0x1 with ".5" or "M" as trailing junk, instead of
blindly treating it as -EINVAL; however, as these cases do not suffer
from the same problems as floating point, they are not worth changing
at this time.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-11-eblake@redhat.com>
2023-05-22 21:04:32 +02:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* Parse stops at 'e', which is not a floating point exponent */
|
|
|
|
do_strtosz_full("1.5e1k", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0);
|
|
|
|
do_strtosz_full("1.5E+0k", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0);
|
|
|
|
do_strtosz_full("1.5E999", qemu_strtosz, 0, EiB * 1.5, 4, -EINVAL, 0);
|
2017-02-21 21:13:56 +01:00
|
|
|
}
|
|
|
|
|
2015-09-16 18:02:57 +02:00
|
|
|
static void test_qemu_strtosz_erange(void)
|
|
|
|
{
|
2023-05-22 21:04:41 +02:00
|
|
|
/* no negative values */
|
2023-05-22 21:04:39 +02:00
|
|
|
do_strtosz(" -0", -ERANGE, 0, 3);
|
|
|
|
do_strtosz("-1", -ERANGE, 0, 2);
|
|
|
|
do_strtosz_full("-2M", qemu_strtosz, -ERANGE, 0, 2, -EINVAL, 0);
|
2023-05-22 21:04:41 +02:00
|
|
|
do_strtosz(" -.0", -ERANGE, 0, 4);
|
|
|
|
do_strtosz_full("-.1k", qemu_strtosz, -ERANGE, 0, 3, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz_full(" -."
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
|
|
|
"00000000000000000000000000000000000000000000000000"
|
2023-05-22 21:04:41 +02:00
|
|
|
"1M", qemu_strtosz, -ERANGE, 0, 354, -EINVAL, 0);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2023-05-22 21:04:33 +02:00
|
|
|
/* 2^64; see strtosz_simple for 2^64-1 */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("18446744073709551616", -ERANGE, 0, 20);
|
2017-02-21 21:13:57 +01:00
|
|
|
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz("20E", -ERANGE, 0, 3);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
2023-05-22 21:04:41 +02:00
|
|
|
/* Fraction tail can cause ERANGE overflow */
|
2023-05-22 21:04:36 +02:00
|
|
|
do_strtosz("15.9999999999999999999999999999999999999999999999999999E",
|
2023-05-22 21:04:41 +02:00
|
|
|
-ERANGE, 0, 56);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* EINVAL has priority over ERANGE */
|
cutils: Set value in all qemu_strtosz* error paths
Making callers determine whether or not *value was populated on error
is not nice for usability. Pre-patch, we have unit tests that check
that *result is left unchanged on most EINVAL errors and set to 0 on
many ERANGE errors. This is subtly different from libc strtoumax()
behavior which returns UINT64_MAX on ERANGE errors, as well as
different from our parse_uint() which slams to 0 on EINVAL on the
grounds that we want our functions to be harder to mis-use than
strtoumax().
Let's audit callers:
- hw/core/numa.c:parse_numa() fixed in the previous patch to check for
errors
- migration/migration-hmp-cmds.c:hmp_migrate_set_parameter(),
monitor/hmp.c:monitor_parse_arguments(),
qapi/opts-visitor.c:opts_type_size(),
qapi/qobject-input-visitor.c:qobject_input_type_size_keyval(),
qemu-img.c:cvtnum_full(), qemu-io-cmds.c:cvtnum(),
target/i386/cpu.c:x86_cpu_parse_featurestr(), and
util/qemu-option.c:parse_option_size() appear to reject all failures
(although some with distinct messages for ERANGE as opposed to
EINVAL), so it doesn't matter what is in the value parameter on
error.
- All remaining callers are in the testsuite, where we can tweak our
expectations to match our new desired behavior.
Advancing to the end of the string parsed on overflow (ERANGE), while
still returning 0, makes sense (UINT64_MAX as a size is unlikely to be
useful); likewise, our size parsing code is complex enough that it's
easier to always return 0 when endptr is NULL but trailing garbage was
found, rather than trying to return the value of the prefix actually
parsed (no current caller cared about the value of the prefix).
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-16-eblake@redhat.com>
2023-05-22 21:04:37 +02:00
|
|
|
do_strtosz_full("100000Pjunk", qemu_strtosz, -ERANGE, 0, 7, -EINVAL, 0);
|
2015-09-16 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
2017-02-21 21:13:58 +01:00
|
|
|
static void test_qemu_strtosz_metric(void)
|
2015-09-16 18:02:57 +02:00
|
|
|
{
|
2023-05-22 21:04:33 +02:00
|
|
|
do_strtosz_metric("12345k", 0, 12345000, 6);
|
|
|
|
do_strtosz_metric("12.345M", 0, 12345000, 7);
|
2023-05-22 21:04:36 +02:00
|
|
|
|
|
|
|
/* Fraction is affected by floating-point rounding */
|
|
|
|
/* This would be 0xfffffffffffffbff with infinite precision */
|
|
|
|
do_strtosz_metric("18.446744073709550591E", 0, 0xfffffffffffffc0cULL, 22);
|
2015-09-16 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
2022-05-25 15:38:48 +02:00
|
|
|
static void test_freq_to_str(void)
|
|
|
|
{
|
2022-06-21 10:34:20 +02:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = freq_to_str(999);
|
|
|
|
g_assert_cmpstr(str, ==, "999 Hz");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = freq_to_str(1000);
|
|
|
|
g_assert_cmpstr(str, ==, "1 KHz");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = freq_to_str(1010);
|
|
|
|
g_assert_cmpstr(str, ==, "1.01 KHz");
|
|
|
|
g_free(str);
|
2022-05-25 15:38:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_size_to_str(void)
|
|
|
|
{
|
2022-06-21 10:34:20 +02:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = size_to_str(0);
|
|
|
|
g_assert_cmpstr(str, ==, "0 B");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = size_to_str(1);
|
|
|
|
g_assert_cmpstr(str, ==, "1 B");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = size_to_str(1016);
|
|
|
|
g_assert_cmpstr(str, ==, "0.992 KiB");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = size_to_str(1024);
|
|
|
|
g_assert_cmpstr(str, ==, "1 KiB");
|
|
|
|
g_free(str);
|
|
|
|
|
|
|
|
str = size_to_str(512ull << 20);
|
|
|
|
g_assert_cmpstr(str, ==, "512 MiB");
|
|
|
|
g_free(str);
|
2022-05-25 15:38:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_iec_binary_prefix(void)
|
|
|
|
{
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(0), ==, "");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(10), ==, "Ki");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(20), ==, "Mi");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(30), ==, "Gi");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(40), ==, "Ti");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(50), ==, "Pi");
|
|
|
|
g_assert_cmpstr(iec_binary_prefix(60), ==, "Ei");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_si_prefix(void)
|
|
|
|
{
|
|
|
|
g_assert_cmpstr(si_prefix(-18), ==, "a");
|
|
|
|
g_assert_cmpstr(si_prefix(-15), ==, "f");
|
|
|
|
g_assert_cmpstr(si_prefix(-12), ==, "p");
|
|
|
|
g_assert_cmpstr(si_prefix(-9), ==, "n");
|
|
|
|
g_assert_cmpstr(si_prefix(-6), ==, "u");
|
|
|
|
g_assert_cmpstr(si_prefix(-3), ==, "m");
|
|
|
|
g_assert_cmpstr(si_prefix(0), ==, "");
|
|
|
|
g_assert_cmpstr(si_prefix(3), ==, "K");
|
|
|
|
g_assert_cmpstr(si_prefix(6), ==, "M");
|
|
|
|
g_assert_cmpstr(si_prefix(9), ==, "G");
|
|
|
|
g_assert_cmpstr(si_prefix(12), ==, "T");
|
|
|
|
g_assert_cmpstr(si_prefix(15), ==, "P");
|
|
|
|
g_assert_cmpstr(si_prefix(18), ==, "E");
|
|
|
|
}
|
|
|
|
|
2013-02-04 19:27:45 +01:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
|
|
|
|
g_test_add_func("/cutils/parse_uint/null", test_parse_uint_null);
|
|
|
|
g_test_add_func("/cutils/parse_uint/empty", test_parse_uint_empty);
|
|
|
|
g_test_add_func("/cutils/parse_uint/whitespace",
|
|
|
|
test_parse_uint_whitespace);
|
|
|
|
g_test_add_func("/cutils/parse_uint/invalid", test_parse_uint_invalid);
|
|
|
|
g_test_add_func("/cutils/parse_uint/trailing", test_parse_uint_trailing);
|
|
|
|
g_test_add_func("/cutils/parse_uint/correct", test_parse_uint_correct);
|
|
|
|
g_test_add_func("/cutils/parse_uint/octal", test_parse_uint_octal);
|
|
|
|
g_test_add_func("/cutils/parse_uint/decimal", test_parse_uint_decimal);
|
|
|
|
g_test_add_func("/cutils/parse_uint/llong_max", test_parse_uint_llong_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/parse_uint/max", test_parse_uint_max);
|
2013-02-04 19:27:45 +01:00
|
|
|
g_test_add_func("/cutils/parse_uint/overflow", test_parse_uint_overflow);
|
|
|
|
g_test_add_func("/cutils/parse_uint/negative", test_parse_uint_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/parse_uint/negzero", test_parse_uint_negzero);
|
2013-02-04 19:27:45 +01:00
|
|
|
g_test_add_func("/cutils/parse_uint_full/trailing",
|
|
|
|
test_parse_uint_full_trailing);
|
|
|
|
g_test_add_func("/cutils/parse_uint_full/correct",
|
|
|
|
test_parse_uint_full_correct);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/parse_uint_full/erange_junk",
|
|
|
|
test_parse_uint_full_erange_junk);
|
2023-05-22 21:04:30 +02:00
|
|
|
g_test_add_func("/cutils/parse_uint_full/null",
|
|
|
|
test_parse_uint_full_null);
|
2013-02-04 19:27:45 +01:00
|
|
|
|
2017-12-22 13:46:23 +01:00
|
|
|
/* qemu_strtoi() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/correct",
|
|
|
|
test_qemu_strtoi_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/null",
|
|
|
|
test_qemu_strtoi_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/empty",
|
|
|
|
test_qemu_strtoi_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/whitespace",
|
|
|
|
test_qemu_strtoi_whitespace);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/invalid",
|
|
|
|
test_qemu_strtoi_invalid);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/trailing",
|
|
|
|
test_qemu_strtoi_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/octal",
|
|
|
|
test_qemu_strtoi_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/decimal",
|
|
|
|
test_qemu_strtoi_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/hex",
|
|
|
|
test_qemu_strtoi_hex);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/max",
|
|
|
|
test_qemu_strtoi_max);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/overflow",
|
|
|
|
test_qemu_strtoi_overflow);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi/min",
|
|
|
|
test_qemu_strtoi_min);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi/underflow",
|
|
|
|
test_qemu_strtoi_underflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi/negative",
|
|
|
|
test_qemu_strtoi_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi/negzero",
|
|
|
|
test_qemu_strtoi_negzero);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/correct",
|
|
|
|
test_qemu_strtoi_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/null",
|
|
|
|
test_qemu_strtoi_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/empty",
|
|
|
|
test_qemu_strtoi_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/negative",
|
|
|
|
test_qemu_strtoi_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/negzero",
|
|
|
|
test_qemu_strtoi_full_negzero);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/trailing",
|
|
|
|
test_qemu_strtoi_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/max",
|
|
|
|
test_qemu_strtoi_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi_full/erange_junk",
|
|
|
|
test_qemu_strtoi_full_erange_junk);
|
2017-12-22 13:46:23 +01:00
|
|
|
|
|
|
|
/* qemu_strtoui() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/correct",
|
|
|
|
test_qemu_strtoui_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/null",
|
|
|
|
test_qemu_strtoui_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/empty",
|
|
|
|
test_qemu_strtoui_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/whitespace",
|
|
|
|
test_qemu_strtoui_whitespace);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/invalid",
|
|
|
|
test_qemu_strtoui_invalid);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/trailing",
|
|
|
|
test_qemu_strtoui_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/octal",
|
|
|
|
test_qemu_strtoui_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/decimal",
|
|
|
|
test_qemu_strtoui_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/hex",
|
|
|
|
test_qemu_strtoui_hex);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui/wrap",
|
|
|
|
test_qemu_strtoui_wrap);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui/max",
|
|
|
|
test_qemu_strtoui_max);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/overflow",
|
|
|
|
test_qemu_strtoui_overflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/underflow",
|
|
|
|
test_qemu_strtoui_underflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui/negative",
|
|
|
|
test_qemu_strtoui_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui/negzero",
|
|
|
|
test_qemu_strtoui_negzero);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/correct",
|
|
|
|
test_qemu_strtoui_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/null",
|
|
|
|
test_qemu_strtoui_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/empty",
|
|
|
|
test_qemu_strtoui_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/negative",
|
|
|
|
test_qemu_strtoui_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/negzero",
|
|
|
|
test_qemu_strtoui_full_negzero);
|
2017-12-22 13:46:23 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/trailing",
|
|
|
|
test_qemu_strtoui_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/max",
|
|
|
|
test_qemu_strtoui_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoui_full/erange_junk",
|
|
|
|
test_qemu_strtoui_full_erange_junk);
|
2017-12-22 13:46:23 +01:00
|
|
|
|
2015-07-20 01:02:17 +02:00
|
|
|
/* qemu_strtol() tests */
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/correct",
|
|
|
|
test_qemu_strtol_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/null",
|
|
|
|
test_qemu_strtol_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/empty",
|
|
|
|
test_qemu_strtol_empty);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/whitespace",
|
|
|
|
test_qemu_strtol_whitespace);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/invalid",
|
|
|
|
test_qemu_strtol_invalid);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/trailing",
|
|
|
|
test_qemu_strtol_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/octal",
|
|
|
|
test_qemu_strtol_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/decimal",
|
|
|
|
test_qemu_strtol_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/hex",
|
|
|
|
test_qemu_strtol_hex);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/max",
|
|
|
|
test_qemu_strtol_max);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol/overflow",
|
|
|
|
test_qemu_strtol_overflow);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/min",
|
|
|
|
test_qemu_strtol_min);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/underflow",
|
|
|
|
test_qemu_strtol_underflow);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/negative",
|
|
|
|
test_qemu_strtol_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol/negzero",
|
|
|
|
test_qemu_strtol_negzero);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/correct",
|
|
|
|
test_qemu_strtol_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/null",
|
|
|
|
test_qemu_strtol_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/empty",
|
|
|
|
test_qemu_strtol_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/negative",
|
|
|
|
test_qemu_strtol_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/negzero",
|
|
|
|
test_qemu_strtol_full_negzero);
|
2015-07-20 01:02:17 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/trailing",
|
|
|
|
test_qemu_strtol_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/max",
|
|
|
|
test_qemu_strtol_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtol_full/erange_junk",
|
|
|
|
test_qemu_strtol_full_erange_junk);
|
2015-07-20 01:02:17 +02:00
|
|
|
|
2015-07-20 01:02:18 +02:00
|
|
|
/* qemu_strtoul() tests */
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/correct",
|
|
|
|
test_qemu_strtoul_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/null",
|
|
|
|
test_qemu_strtoul_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/empty",
|
|
|
|
test_qemu_strtoul_empty);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/whitespace",
|
|
|
|
test_qemu_strtoul_whitespace);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/invalid",
|
|
|
|
test_qemu_strtoul_invalid);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/trailing",
|
|
|
|
test_qemu_strtoul_trailing);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/octal",
|
|
|
|
test_qemu_strtoul_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/decimal",
|
|
|
|
test_qemu_strtoul_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/hex",
|
|
|
|
test_qemu_strtoul_hex);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/wrap",
|
|
|
|
test_qemu_strtoul_wrap);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/max",
|
|
|
|
test_qemu_strtoul_max);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/overflow",
|
|
|
|
test_qemu_strtoul_overflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/underflow",
|
|
|
|
test_qemu_strtoul_underflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul/negative",
|
|
|
|
test_qemu_strtoul_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul/negzero",
|
|
|
|
test_qemu_strtoul_negzero);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/correct",
|
|
|
|
test_qemu_strtoul_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/null",
|
|
|
|
test_qemu_strtoul_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/empty",
|
|
|
|
test_qemu_strtoul_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/negative",
|
|
|
|
test_qemu_strtoul_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/negzero",
|
|
|
|
test_qemu_strtoul_full_negzero);
|
2015-07-20 01:02:18 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/trailing",
|
|
|
|
test_qemu_strtoul_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/max",
|
|
|
|
test_qemu_strtoul_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoul_full/erange_junk",
|
|
|
|
test_qemu_strtoul_full_erange_junk);
|
2015-07-20 01:02:18 +02:00
|
|
|
|
2017-02-21 21:13:50 +01:00
|
|
|
/* qemu_strtoi64() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/correct",
|
|
|
|
test_qemu_strtoi64_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/null",
|
|
|
|
test_qemu_strtoi64_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/empty",
|
|
|
|
test_qemu_strtoi64_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/whitespace",
|
|
|
|
test_qemu_strtoi64_whitespace);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/invalid",
|
2017-02-21 21:13:50 +01:00
|
|
|
test_qemu_strtoi64_invalid);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/trailing",
|
|
|
|
test_qemu_strtoi64_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/octal",
|
|
|
|
test_qemu_strtoi64_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/decimal",
|
|
|
|
test_qemu_strtoi64_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/hex",
|
|
|
|
test_qemu_strtoi64_hex);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/max",
|
|
|
|
test_qemu_strtoi64_max);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/overflow",
|
|
|
|
test_qemu_strtoi64_overflow);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/min",
|
|
|
|
test_qemu_strtoi64_min);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/underflow",
|
|
|
|
test_qemu_strtoi64_underflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/negative",
|
|
|
|
test_qemu_strtoi64_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64/negzero",
|
|
|
|
test_qemu_strtoi64_negzero);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/correct",
|
|
|
|
test_qemu_strtoi64_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/null",
|
|
|
|
test_qemu_strtoi64_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/empty",
|
|
|
|
test_qemu_strtoi64_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/negative",
|
|
|
|
test_qemu_strtoi64_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/negzero",
|
|
|
|
test_qemu_strtoi64_full_negzero);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/trailing",
|
|
|
|
test_qemu_strtoi64_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/max",
|
|
|
|
test_qemu_strtoi64_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtoi64_full/erange_junk",
|
|
|
|
test_qemu_strtoi64_full_erange_junk);
|
2017-02-21 21:13:50 +01:00
|
|
|
|
|
|
|
/* qemu_strtou64() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/correct",
|
|
|
|
test_qemu_strtou64_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/null",
|
|
|
|
test_qemu_strtou64_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/empty",
|
|
|
|
test_qemu_strtou64_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/whitespace",
|
|
|
|
test_qemu_strtou64_whitespace);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/invalid",
|
|
|
|
test_qemu_strtou64_invalid);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/trailing",
|
|
|
|
test_qemu_strtou64_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/octal",
|
|
|
|
test_qemu_strtou64_octal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/decimal",
|
|
|
|
test_qemu_strtou64_decimal);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/hex",
|
|
|
|
test_qemu_strtou64_hex);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64/wrap",
|
|
|
|
test_qemu_strtou64_wrap);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64/max",
|
|
|
|
test_qemu_strtou64_max);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/overflow",
|
|
|
|
test_qemu_strtou64_overflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/underflow",
|
|
|
|
test_qemu_strtou64_underflow);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64/negative",
|
|
|
|
test_qemu_strtou64_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64/negzero",
|
|
|
|
test_qemu_strtou64_negzero);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/correct",
|
|
|
|
test_qemu_strtou64_full_correct);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/null",
|
|
|
|
test_qemu_strtou64_full_null);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/empty",
|
|
|
|
test_qemu_strtou64_full_empty);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/negative",
|
|
|
|
test_qemu_strtou64_full_negative);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/negzero",
|
|
|
|
test_qemu_strtou64_full_negzero);
|
2017-02-21 21:13:50 +01:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/trailing",
|
|
|
|
test_qemu_strtou64_full_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/max",
|
|
|
|
test_qemu_strtou64_full_max);
|
test-cutils: Test more integer corner cases
We have quite a few undertested and underdocumented integer parsing
corner cases. To ensure that any changes we make in the code are
intentional rather than accidental semantic changes, it is time to add
more unit tests of existing behavior.
In particular, this demonstrates that parse_uint() and qemu_strtou64()
behave differently. For "-0", it's hard to argue why parse_uint needs
to reject it (it's not a negative integer), but the documentation sort
of mentions it; but it is intentional that all other negative values
are treated as ERANGE with value 0 (compared to qemu_strtou64()
treating "-2" as success and UINT64_MAX-1, for example).
Also, when mixing overflow/underflow with a check for no trailing
junk, parse_uint_full favors ERANGE over EINVAL, while qemu_strto[iu]*
favor EINVAL. This behavior is outside the C standard, so we can pick
whatever we want, but it would be nice to be consistent.
Note that C requires that "9223372036854775808" fail strtoll() with
ERANGE/INT64_MAX, but "-9223372036854775808" pass with INT64_MIN; we
weren't testing this. For strtol(), the behavior depends on whether
long is 32- or 64-bits (the cutoff point either being the same as
strtoll() or at "-2147483648"). Meanwhile, C is clear that
"-18446744073709551615" pass stroull() (but not strtoll) with value 1,
even though we want it to fail parse_uint(). And although
qemu_strtoui() has no C counterpart, it makes more sense if we design
it like 32-bit strtoul() (that is, where "-4294967296" be an alternate
acceptable spelling for "1", but "-0xffffffff00000001" should be
treated as overflow and return 0xffffffff rather than 1). We aren't
there yet, so some of the tests added in this patch have FIXME
comments.
However, note that C2x will (likely) be adding a SILENT semantic
change, where C17 strtol("0b1", &ep, 2) returns 0 with ep="b1", but
C2x will have it return 1 with ep="". I did not feel like adding
testing for those corner cases, in part because the next version of C
is not standard and libc support for binary parsing is not yet
wide-spread (as of this patch, glibc.git still misparses bare "0b":
https://sourceware.org/bugzilla/show_bug.cgi?id=30371).
Message-Id: <20230522190441.64278-5-eblake@redhat.com>
[eblake: fix a few typos spotted by Hanna]
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
[eblake: fix typo on platforms with 32-bit long]
Signed-off-by: Eric Blake <eblake@redhat.com>
2023-05-22 21:04:26 +02:00
|
|
|
g_test_add_func("/cutils/qemu_strtou64_full/erange_junk",
|
|
|
|
test_qemu_strtou64_full_erange_junk);
|
2015-07-20 01:02:20 +02:00
|
|
|
|
test-cutils: Add coverage of qemu_strtod
It's hard to tweak code for consistency if I can't prove what will or
won't break from those tweaks. Time to add unit tests for
qemu_strtod() and qemu_strtod_finite().
Among other things, I wrote a check whether we have C99 semantics for
strtod("0x1") (which MUST parse hex numbers) rather than C89 (which
must stop parsing at 'x'). These days, I suspect that is okay; but if
it fails CI checks, knowing the difference will help us decide what we
want to do about it. Note that C2x, while not final at the time of
this patch, has been considering whether to make strtol("0b1") parse
as 1 with no slop instead of the C17 parse of 0 with slop "b1"; that
decision may also bleed over to strtod(). But for now, I didn't think
it worth adding unit tests on that front (to strtol or strtod) as
things may still change.
Likewise, there are plenty more corner cases of strtod proper that I
don't explicitly test here, but there are enough unit tests added here
that it covers all the branches reached in our wrappers. In
particular, it demonstrates the difference on when *value is left
uninitialized, which an upcoming patch will normalize.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-Id: <20230522190441.64278-10-eblake@redhat.com>
2023-05-22 21:04:31 +02:00
|
|
|
/* qemu_strtod() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/simple",
|
|
|
|
test_qemu_strtod_simple);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/einval",
|
|
|
|
test_qemu_strtod_einval);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/erange",
|
|
|
|
test_qemu_strtod_erange);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/nonfinite",
|
|
|
|
test_qemu_strtod_nonfinite);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/trailing",
|
|
|
|
test_qemu_strtod_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod/erange_junk",
|
|
|
|
test_qemu_strtod_erange_junk);
|
|
|
|
|
|
|
|
/* qemu_strtod_finite() tests */
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/simple",
|
|
|
|
test_qemu_strtod_finite_simple);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/einval",
|
|
|
|
test_qemu_strtod_finite_einval);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/erange",
|
|
|
|
test_qemu_strtod_finite_erange);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/nonfinite",
|
|
|
|
test_qemu_strtod_finite_nonfinite);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/trailing",
|
|
|
|
test_qemu_strtod_finite_trailing);
|
|
|
|
g_test_add_func("/cutils/qemu_strtod_finite/erange_junk",
|
|
|
|
test_qemu_strtod_finite_erange_junk);
|
|
|
|
|
|
|
|
/* qemu_strtosz() tests */
|
2015-09-16 18:02:57 +02:00
|
|
|
g_test_add_func("/cutils/strtosz/simple",
|
|
|
|
test_qemu_strtosz_simple);
|
2021-02-11 21:44:35 +01:00
|
|
|
g_test_add_func("/cutils/strtosz/hex",
|
|
|
|
test_qemu_strtosz_hex);
|
2015-09-16 18:02:57 +02:00
|
|
|
g_test_add_func("/cutils/strtosz/units",
|
|
|
|
test_qemu_strtosz_units);
|
|
|
|
g_test_add_func("/cutils/strtosz/float",
|
|
|
|
test_qemu_strtosz_float);
|
2017-02-21 21:13:55 +01:00
|
|
|
g_test_add_func("/cutils/strtosz/invalid",
|
|
|
|
test_qemu_strtosz_invalid);
|
2017-02-21 21:13:56 +01:00
|
|
|
g_test_add_func("/cutils/strtosz/trailing",
|
|
|
|
test_qemu_strtosz_trailing);
|
2015-09-16 18:02:57 +02:00
|
|
|
g_test_add_func("/cutils/strtosz/erange",
|
|
|
|
test_qemu_strtosz_erange);
|
2017-02-21 21:13:58 +01:00
|
|
|
g_test_add_func("/cutils/strtosz/metric",
|
|
|
|
test_qemu_strtosz_metric);
|
2015-09-16 18:02:57 +02:00
|
|
|
|
2022-05-25 15:38:48 +02:00
|
|
|
g_test_add_func("/cutils/size_to_str",
|
|
|
|
test_size_to_str);
|
|
|
|
g_test_add_func("/cutils/freq_to_str",
|
|
|
|
test_freq_to_str);
|
|
|
|
g_test_add_func("/cutils/iec_binary_prefix",
|
|
|
|
test_iec_binary_prefix);
|
|
|
|
g_test_add_func("/cutils/si_prefix",
|
|
|
|
test_si_prefix);
|
2013-02-04 19:27:45 +01:00
|
|
|
return g_test_run();
|
|
|
|
}
|