From 694baf57ae103954e2337d1fa22d1dcdfa8e2f5a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:45 +0100 Subject: [PATCH 01/24] test-qemu-opts: Cover qemu_opts_parse() The new tests demonstrate a few bugs, all clearly marked. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-2-git-send-email-armbru@redhat.com> [A few additional test cases squashed in, see Message-ID: <871supjijq.fsf@dusky.pond.sub.org>] --- tests/test-qemu-opts.c | 332 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 329 insertions(+), 3 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index a505a3e059..310485bb2e 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "qapi/qmp/qstring.h" #include "qemu/config-file.h" @@ -29,6 +30,9 @@ static QemuOptsList opts_list_01 = { },{ .name = "number1", .type = QEMU_OPT_NUMBER, + },{ + .name = "number2", + .type = QEMU_OPT_NUMBER, }, { /* end of list */ } }, @@ -41,15 +45,24 @@ static QemuOptsList opts_list_02 = { { .name = "str1", .type = QEMU_OPT_STRING, - },{ - .name = "bool1", - .type = QEMU_OPT_BOOL, },{ .name = "str2", .type = QEMU_OPT_STRING, + },{ + .name = "bool1", + .type = QEMU_OPT_BOOL, + },{ + .name = "bool2", + .type = QEMU_OPT_BOOL, },{ .name = "size1", .type = QEMU_OPT_SIZE, + },{ + .name = "size2", + .type = QEMU_OPT_SIZE, + },{ + .name = "size3", + .type = QEMU_OPT_SIZE, }, { /* end of list */ } }, @@ -57,6 +70,7 @@ static QemuOptsList opts_list_02 = { static QemuOptsList opts_list_03 = { .name = "opts_list_03", + .implied_opt_name = "implied", .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head), .desc = { /* no elements => accept any params */ @@ -421,6 +435,314 @@ static void test_qemu_opts_set(void) g_assert(opts == NULL); } +static int opts_count_iter(void *opaque, const char *name, const char *value, + Error **errp) +{ + (*(size_t *)opaque)++; + return 0; +} + +static size_t opts_count(QemuOpts *opts) +{ + size_t n = 0; + + qemu_opt_foreach(opts, opts_count_iter, &n, NULL); + return n; +} + +static void test_opts_parse(void) +{ + Error *err = NULL; + QemuOpts *opts; + char long_key[129]; + char *params; + + /* Nothing */ + opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 0); + + /* Empty key */ + opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); + + /* Long key */ + memset(long_key, 'a', 127); + long_key[127] = 'z'; + long_key[128] = 0; + params = g_strdup_printf("%s=v", long_key); + opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v"); + + /* Overlong key gets truncated */ + opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort); + g_assert(opts_count(opts) == 1); + long_key[127] = 0; + g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v"); + g_free(params); + + /* Multiple keys, last one wins */ + opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 3); + g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3"); + g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x"); + + /* Except when it doesn't */ + opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 0); + g_assert_cmpstr(qemu_opts_id(opts), ==, "foo"); + + /* TODO Cover low-level access to repeated keys */ + + /* Trailing comma is ignored */ + opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y"); + + /* Except when it isn't */ + opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on"); + + /* Duplicate ID */ + opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + /* TODO Cover .merge_lists = true */ + + /* Buggy ID recognition */ + opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */ + g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar"); + + /* Anti-social ID */ + opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + + /* Implied value */ + opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 3); + g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on"); + g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); + g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); + + /* Implied key */ + opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true, + &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 3); + g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an"); + g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off"); + g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, ""); + + /* Implied key with empty value */ + opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ""); + + /* Implied key with comma value */ + opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ","); + g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1"); + + /* Empty key is not an implied key */ + opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val"); + + /* Unknown key */ + opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + + qemu_opts_reset(&opts_list_01); + qemu_opts_reset(&opts_list_03); +} + +static void test_opts_parse_bool(void) +{ + Error *err = NULL; + QemuOpts *opts; + + opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert(qemu_opt_get_bool(opts, "bool1", false)); + g_assert(!qemu_opt_get_bool(opts, "bool2", true)); + + opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + + qemu_opts_reset(&opts_list_02); +} + +static void test_opts_parse_number(void) +{ + Error *err = NULL; + QemuOpts *opts; + + /* Lower limit zero */ + opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); + + /* Upper limit 2^64-1 */ + opts = qemu_opts_parse(&opts_list_01, + "number1=18446744073709551615,number2=-1", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); + g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX); + + /* Above upper limit */ + opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616", + false, &error_abort); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); + + /* Below lower limit */ + opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616", + false, &error_abort); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); + + /* Hex and octal */ + opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); + g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42); + + /* Invalid */ + opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); + opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + + /* Leading whitespace */ + opts = qemu_opts_parse(&opts_list_01, "number1= \t42", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42); + + /* Trailing crap */ + opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + + qemu_opts_reset(&opts_list_01); +} + +static void test_opts_parse_size(void) +{ + Error *err = NULL; + QemuOpts *opts; + + /* Lower limit zero */ + opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); + + /* Note: precision is 53 bits since we're parsing with strtod() */ + + /* Around limit of precision: 2^53-1, 2^53, 2^54 */ + opts = qemu_opts_parse(&opts_list_02, + "size1=9007199254740991," + "size2=9007199254740992," + "size3=9007199254740993", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 3); + g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), + ==, 0x1fffffffffffff); + g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), + ==, 0x20000000000000); + g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1), + ==, 0x20000000000000); + + /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ + opts = qemu_opts_parse(&opts_list_02, + "size1=9223372036854774784," /* 7ffffffffffffc00 */ + "size2=9223372036854775295", /* 7ffffffffffffdff */ + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), + ==, 0x7ffffffffffffc00); + g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), + ==, 0x7ffffffffffffc00); + + /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ + opts = qemu_opts_parse(&opts_list_02, + "size1=18446744073709549568," /* fffffffffffff800 */ + "size2=18446744073709550591", /* fffffffffffffbff */ + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1), + ==, 0xfffffffffffff800); + g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1), + ==, 0xfffffffffffff800); + + /* Beyond limits */ + opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + opts = qemu_opts_parse(&opts_list_02, + "size1=18446744073709550592", /* fffffffffffffc00 */ + false, &error_abort); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); + + /* Suffixes */ + opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 3); + g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8); + g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536); + g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE); + opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T", + false, &error_abort); + g_assert_cmpuint(opts_count(opts), ==, 2); + g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10); + g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), + ==, 16777215 * T_BYTE); + + /* Beyond limit with suffix */ + opts = qemu_opts_parse(&opts_list_02, "size1=16777216T", + false, &error_abort); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); + + /* Trailing crap */ + opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err); + error_free_or_abort(&err); + g_assert(!opts); + opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &error_abort); + /* BUG: should reject */ + g_assert_cmpuint(opts_count(opts), ==, 1); + g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 16 * G_BYTE); + + qemu_opts_reset(&opts_list_02); +} + int main(int argc, char *argv[]) { register_opts(); @@ -435,6 +757,10 @@ int main(int argc, char *argv[]) g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset); g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset); g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set); + g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse); + g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool); + g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number); + g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size); g_test_run(); return 0; } From 8ee8409eff5643c677d6e5dce6620355a89c80f8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:46 +0100 Subject: [PATCH 02/24] option: Assert value string isn't null Plenty of code relies on QemuOpt member @str not being null, including qemu_opts_print(), qemu_opts_to_qdict(), and callbacks passed to qemu_opt_foreach(). Begs the question whether it can be null. Only opt_set() creates QemuOpt. It sets member @str to its argument @value. Passing null for @value would plant a time bomb. Callers: * opts_do_parse() can't pass null. * qemu_opt_set() passes its argument @value. Callers: - qemu_opts_from_qdict_1() can't pass null - qemu_opts_set() passes its argument @value, but none of its callers pass null. - Many more outside qemu-option.c, but they shouldn't pass null, either. Assert member @str isn't null, so that misuse is caught right away. Simplify parse_option_bool(), parse_option_number() and parse_option_size() accordingly. Best viewed with whitespace changes ignored. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-3-git-send-email-armbru@redhat.com> --- util/qemu-option.c | 89 ++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index d611946333..9708668847 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -128,17 +128,13 @@ int get_param_value(char *buf, int buf_size, static void parse_option_bool(const char *name, const char *value, bool *ret, Error **errp) { - if (value != NULL) { - if (!strcmp(value, "on")) { - *ret = 1; - } else if (!strcmp(value, "off")) { - *ret = 0; - } else { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, - name, "'on' or 'off'"); - } - } else { + if (!strcmp(value, "on")) { *ret = 1; + } else if (!strcmp(value, "off")) { + *ret = 0; + } else { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + name, "'on' or 'off'"); } } @@ -148,16 +144,12 @@ static void parse_option_number(const char *name, const char *value, char *postfix; uint64_t number; - if (value != NULL) { - number = strtoull(value, &postfix, 0); - if (*postfix != '\0') { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); - return; - } - *ret = number; - } else { + number = strtoull(value, &postfix, 0); + if (*postfix != '\0') { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); + return; } + *ret = number; } static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, @@ -180,39 +172,35 @@ void parse_option_size(const char *name, const char *value, char *postfix; double sizef; - if (value != NULL) { - sizef = strtod(value, &postfix); - if (sizef < 0 || sizef > UINT64_MAX) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, - "a non-negative number below 2^64"); - return; - } - switch (*postfix) { - case 'T': - sizef *= 1024; - /* fall through */ - case 'G': - sizef *= 1024; - /* fall through */ - case 'M': - sizef *= 1024; - /* fall through */ - case 'K': - case 'k': - sizef *= 1024; - /* fall through */ - case 'b': - case '\0': - *ret = (uint64_t) sizef; - break; - default: - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); - error_append_hint(errp, "You may use k, M, G or T suffixes for " - "kilobytes, megabytes, gigabytes and terabytes.\n"); - return; - } - } else { + sizef = strtod(value, &postfix); + if (sizef < 0 || sizef > UINT64_MAX) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, + "a non-negative number below 2^64"); + return; + } + switch (*postfix) { + case 'T': + sizef *= 1024; + /* fall through */ + case 'G': + sizef *= 1024; + /* fall through */ + case 'M': + sizef *= 1024; + /* fall through */ + case 'K': + case 'k': + sizef *= 1024; + /* fall through */ + case 'b': + case '\0': + *ret = (uint64_t) sizef; + break; + default: error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); + error_append_hint(errp, "You may use k, M, G or T suffixes for " + "kilobytes, megabytes, gigabytes and terabytes.\n"); + return; } } @@ -566,6 +554,7 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value, } opt->desc = desc; opt->str = g_strdup(value); + assert(opt->str); qemu_opt_parse(opt, &local_err); if (local_err) { error_propagate(errp, local_err); From 73245450b302931ad291de5d8d0f0cb5e9ca3ee6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:47 +0100 Subject: [PATCH 03/24] test-cutils: Add missing qemu_strtol()... endptr checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1487708048-2131-4-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 20b0f59ba2..71681dc670 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -262,6 +262,7 @@ static void test_qemu_strtol_empty(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtol_whitespace(void) @@ -275,6 +276,7 @@ static void test_qemu_strtol_whitespace(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtol_invalid(void) @@ -288,6 +290,7 @@ static void test_qemu_strtol_invalid(void) err = qemu_strtol(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtol_trailing(void) @@ -548,6 +551,7 @@ static void test_qemu_strtoul_empty(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoul_whitespace(void) @@ -561,6 +565,7 @@ static void test_qemu_strtoul_whitespace(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoul_invalid(void) @@ -574,6 +579,7 @@ static void test_qemu_strtoul_invalid(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoul_trailing(void) @@ -829,6 +835,7 @@ static void test_qemu_strtoll_empty(void) err = qemu_strtoll(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoll_whitespace(void) @@ -842,6 +849,7 @@ static void test_qemu_strtoll_whitespace(void) err = qemu_strtoll(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoll_invalid(void) @@ -855,6 +863,7 @@ static void test_qemu_strtoll_invalid(void) err = qemu_strtoll(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoll_trailing(void) @@ -1113,6 +1122,7 @@ static void test_qemu_strtoull_empty(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoull_whitespace(void) @@ -1126,6 +1136,7 @@ static void test_qemu_strtoull_whitespace(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoull_invalid(void) @@ -1139,6 +1150,7 @@ static void test_qemu_strtoull_invalid(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == str); } static void test_qemu_strtoull_trailing(void) From bc7c08a2c375acb7ae4d433054415588b176d34c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:48 +0100 Subject: [PATCH 04/24] test-cutils: Clean up qemu_strtoul() result checks Use unsigned comparisons to check the result of qemu_strtoul() and strtoull(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-5-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 71681dc670..749aaa938a 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -523,7 +523,7 @@ static void test_qemu_strtoul_correct(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345); + g_assert_cmpuint(res, ==, 12345); g_assert(endptr == str + 5); } @@ -593,7 +593,7 @@ static void test_qemu_strtoul_trailing(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + 3); } @@ -608,7 +608,7 @@ static void test_qemu_strtoul_octal(void) err = qemu_strtoul(str, &endptr, 8, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0123); + g_assert_cmpuint(res, ==, 0123); g_assert(endptr == str + strlen(str)); res = 999; @@ -616,7 +616,7 @@ static void test_qemu_strtoul_octal(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0123); + g_assert_cmpuint(res, ==, 0123); g_assert(endptr == str + strlen(str)); } @@ -631,7 +631,7 @@ static void test_qemu_strtoul_decimal(void) err = qemu_strtoul(str, &endptr, 10, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + strlen(str)); str = "123"; @@ -640,7 +640,7 @@ static void test_qemu_strtoul_decimal(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + strlen(str)); } @@ -655,7 +655,7 @@ static void test_qemu_strtoul_hex(void) err = qemu_strtoul(str, &endptr, 16, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x123); + g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); str = "0x123"; @@ -664,7 +664,7 @@ static void test_qemu_strtoul_hex(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x123); + g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); } @@ -679,7 +679,7 @@ static void test_qemu_strtoul_max(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_cmphex(res, ==, ULONG_MAX); g_assert(endptr == str + strlen(str)); g_free(str); } @@ -695,7 +695,7 @@ static void test_qemu_strtoul_overflow(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_cmphex(res, ==, ULONG_MAX); g_assert(endptr == str + strlen(str)); } @@ -710,7 +710,7 @@ static void test_qemu_strtoul_underflow(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, -1ul); + g_assert_cmpuint(res, ==, -1ul); g_assert(endptr == str + strlen(str)); } @@ -725,7 +725,7 @@ static void test_qemu_strtoul_negative(void) err = qemu_strtoul(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, -321ul); + g_assert_cmpuint(res, ==, -321ul); g_assert(endptr == str + strlen(str)); } @@ -738,7 +738,7 @@ static void test_qemu_strtoul_full_correct(void) err = qemu_strtoul(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); } static void test_qemu_strtoul_full_null(void) @@ -769,7 +769,7 @@ static void test_qemu_strtoul_full_negative(void) err = qemu_strtoul(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, -321ul); + g_assert_cmpuint(res, ==, -321ul); } static void test_qemu_strtoul_full_trailing(void) @@ -792,7 +792,7 @@ static void test_qemu_strtoul_full_max(void) err = qemu_strtoul(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, ULONG_MAX); + g_assert_cmphex(res, ==, ULONG_MAX); g_free(str); } @@ -1094,7 +1094,7 @@ static void test_qemu_strtoull_correct(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 12345); + g_assert_cmpuint(res, ==, 12345); g_assert(endptr == str + 5); } @@ -1164,7 +1164,7 @@ static void test_qemu_strtoull_trailing(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + 3); } @@ -1179,7 +1179,7 @@ static void test_qemu_strtoull_octal(void) err = qemu_strtoull(str, &endptr, 8, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0123); + g_assert_cmpuint(res, ==, 0123); g_assert(endptr == str + strlen(str)); endptr = &f; @@ -1187,7 +1187,7 @@ static void test_qemu_strtoull_octal(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0123); + g_assert_cmpuint(res, ==, 0123); g_assert(endptr == str + strlen(str)); } @@ -1202,7 +1202,7 @@ static void test_qemu_strtoull_decimal(void) err = qemu_strtoull(str, &endptr, 10, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + strlen(str)); str = "123"; @@ -1211,7 +1211,7 @@ static void test_qemu_strtoull_decimal(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 123); + g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + strlen(str)); } @@ -1226,7 +1226,7 @@ static void test_qemu_strtoull_hex(void) err = qemu_strtoull(str, &endptr, 16, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x123); + g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); str = "0x123"; @@ -1235,7 +1235,7 @@ static void test_qemu_strtoull_hex(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x123); + g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); } @@ -1250,7 +1250,7 @@ static void test_qemu_strtoull_max(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert_cmphex(res, ==, ULLONG_MAX); g_assert(endptr == str + strlen(str)); g_free(str); } @@ -1266,7 +1266,7 @@ static void test_qemu_strtoull_overflow(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert_cmphex(res, ==, ULLONG_MAX); g_assert(endptr == str + strlen(str)); } @@ -1281,7 +1281,7 @@ static void test_qemu_strtoull_underflow(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert_cmpint(res, ==, -1); + g_assert_cmphex(res, ==, -1ull); g_assert(endptr == str + strlen(str)); } @@ -1296,7 +1296,7 @@ static void test_qemu_strtoull_negative(void) err = qemu_strtoull(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, -321); + g_assert_cmpuint(res, ==, -321ull); g_assert(endptr == str + strlen(str)); } @@ -1309,7 +1309,7 @@ static void test_qemu_strtoull_full_correct(void) err = qemu_strtoull(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 18446744073709551614LLU); + g_assert_cmpuint(res, ==, 18446744073709551614ull); } static void test_qemu_strtoull_full_null(void) @@ -1342,7 +1342,7 @@ static void test_qemu_strtoull_full_negative(void) err = qemu_strtoull(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 18446744073709551295LLU); + g_assert_cmpuint(res, ==, -321ull); } static void test_qemu_strtoull_full_trailing(void) @@ -1365,7 +1365,7 @@ static void test_qemu_strtoull_full_max(void) err = qemu_strtoull(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert_cmphex(res, ==, ULLONG_MAX); g_free(str); } From 4295f879becfbbb9f4330489311586b96915d920 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:49 +0100 Subject: [PATCH 05/24] util/cutils: Rewrite documentation of qemu_strtol() & friends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following documentation bugs: * Fails to document that null @nptr is safe. * Fails to document that we return -EINVAL when no conversion could be performed (commit 47d4be1). * Confuses long long with int64_t, and unsigned long long with uint64_t. * Claims the unsigned conversions can underflow. They can't. While there, mark problematic assumptions that int64_t is long long, and uint64_t is unsigned long long with FIXME comments. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1487708048-2131-6-git-send-email-armbru@redhat.com> --- util/cutils.c | 80 +++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 4fefcf3be3..1ae2a0814b 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -265,9 +265,6 @@ int64_t qemu_strtosz(const char *nptr, char **end) static int check_strtox_error(const char *p, char *endptr, const char **next, int err) { - /* If no conversion was performed, prefer BSD behavior over glibc - * behavior. - */ if (err == 0 && endptr == p) { err = EINVAL; } @@ -281,30 +278,28 @@ static int check_strtox_error(const char *p, char *endptr, const char **next, } /** - * QEMU wrappers for strtol(), strtoll(), strtoul(), strotull() C functions. + * Convert string @nptr to a long integer, and store it in @result. * - * Convert ASCII string @nptr to a long integer value - * from the given @base. Parameters @nptr, @endptr, @base - * follows same semantics as strtol() C function. + * This is a wrapper around strtol() that is harder to misuse. + * Semantics of @nptr, @endptr, @base match strtol() with differences + * noted below. * - * Unlike from strtol() function, if @endptr is not NULL, this - * function will return -EINVAL whenever it cannot fully convert - * the string in @nptr with given @base to a long. This function returns - * the result of the conversion only through the @result parameter. + * @nptr may be null, and no conversion is performed then. * - * If NULL is passed in @endptr, then the whole string in @ntpr - * is a number otherwise it returns -EINVAL. + * If no conversion is performed, store @nptr in *@endptr and return + * -EINVAL. * - * RETURN VALUE - * Unlike from strtol() function, this wrapper returns either - * -EINVAL or the errno set by strtol() function (e.g -ERANGE). - * If the conversion overflows, -ERANGE is returned, and @result - * is set to the max value of the desired type - * (e.g. LONG_MAX, LLONG_MAX, ULONG_MAX, ULLONG_MAX). If the case - * of underflow, -ERANGE is returned, and @result is set to the min - * value of the desired type. For strtol(), strtoll(), @result is set to - * LONG_MIN, LLONG_MIN, respectively, and for strtoul(), strtoull() it - * is set to 0. + * If @endptr is null, and the string isn't fully converted, return + * -EINVAL. This is the case when the pointer that would be stored in + * a non-null @endptr points to a character other than '\0'. + * + * If the conversion overflows @result, store LONG_MAX in @result, + * and return -ERANGE. + * + * If the conversion underflows @result, store LONG_MIN in @result, + * and return -ERANGE. + * + * Else store the converted value in @result, and return zero. */ int qemu_strtol(const char *nptr, const char **endptr, int base, long *result) @@ -325,17 +320,29 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, } /** - * Converts ASCII string to an unsigned long integer. + * Convert string @nptr to an unsigned long, and store it in @result. * - * If string contains a negative number, value will be converted to - * the unsigned representation of the signed value, unless the original - * (nonnegated) value would overflow, in this case, it will set @result - * to ULONG_MAX, and return ERANGE. + * This is a wrapper around strtoul() that is harder to misuse. + * Semantics of @nptr, @endptr, @base match strtoul() with differences + * noted below. * - * The same behavior holds, for qemu_strtoull() but sets @result to - * ULLONG_MAX instead of ULONG_MAX. + * @nptr may be null, and no conversion is performed then. * - * See qemu_strtol() documentation for more info. + * If no conversion is performed, store @nptr in *@endptr and return + * -EINVAL. + * + * If @endptr is null, and the string isn't fully converted, return + * -EINVAL. This is the case when the pointer that would be stored in + * a non-null @endptr points to a character other than '\0'. + * + * If the conversion overflows @result, store ULONG_MAX in @result, + * and return -ERANGE. + * + * Else store the converted value in @result, and return zero. + * + * Note that a number with a leading minus sign gets converted without + * the minus sign, checked for overflow (see above), then negated (in + * @result's type). This is exactly how strtoul() works. */ int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result) @@ -360,9 +367,10 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, } /** - * Converts ASCII string to a long long integer. + * Convert string @nptr to an int64_t. * - * See qemu_strtol() documentation for more info. + * Works like qemu_strtol(), except it stores INT64_MAX on overflow, + * and INT_MIN on underflow. */ int qemu_strtoll(const char *nptr, const char **endptr, int base, int64_t *result) @@ -376,6 +384,7 @@ int qemu_strtoll(const char *nptr, const char **endptr, int base, err = -EINVAL; } else { errno = 0; + /* FIXME This assumes int64_t is long long */ *result = strtoll(nptr, &p, base); err = check_strtox_error(nptr, p, endptr, errno); } @@ -383,9 +392,9 @@ int qemu_strtoll(const char *nptr, const char **endptr, int base, } /** - * Converts ASCII string to an unsigned long long integer. + * Convert string @nptr to an uint64_t. * - * See qemu_strtol() documentation for more info. + * Works like qemu_strtoul(), except it stores UINT64_MAX on overflow. */ int qemu_strtoull(const char *nptr, const char **endptr, int base, uint64_t *result) @@ -399,6 +408,7 @@ int qemu_strtoull(const char *nptr, const char **endptr, int base, err = -EINVAL; } else { errno = 0; + /* FIXME This assumes uint64_t is unsigned long long */ *result = strtoull(nptr, &p, base); /* Windows returns 1 for negative out-of-range values. */ if (errno == ERANGE) { From b30d188677456b17c1cd68969e08ddc634cef644 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:50 +0100 Subject: [PATCH 06/24] util/cutils: Rename qemu_strtoll(), qemu_strtoull() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name qemu_strtoll() suggests conversion to long long, but it actually converts to int64_t. Rename to qemu_strtoi64(). The name qemu_strtoull() suggests conversion to unsigned long long, but it actually converts to uint64_t. Rename to qemu_strtou64(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1487708048-2131-7-git-send-email-armbru@redhat.com> --- include/qemu/cutils.h | 6 +- qobject/qdict.c | 2 +- qtest.c | 34 ++-- tests/test-cutils.c | 366 +++++++++++++++++++++++------------------- util/cutils.c | 4 +- util/log.c | 4 +- 6 files changed, 224 insertions(+), 192 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 8033929139..f922223f04 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -130,9 +130,9 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, long *result); int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result); -int qemu_strtoll(const char *nptr, const char **endptr, int base, - int64_t *result); -int qemu_strtoull(const char *nptr, const char **endptr, int base, +int qemu_strtoi64(const char *nptr, const char **endptr, int base, + int64_t *result); +int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result); int parse_uint(const char *s, unsigned long long *value, char **endptr, diff --git a/qobject/qdict.c b/qobject/qdict.c index 197b0fbd47..4be7d3eb72 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -767,7 +767,7 @@ static int qdict_is_list(QDict *maybe_list, Error **errp) for (ent = qdict_first(maybe_list); ent != NULL; ent = qdict_next(maybe_list, ent)) { - if (qemu_strtoll(ent->key, NULL, 10, &val) == 0) { + if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { if (is_list == -1) { is_list = 1; } else if (!is_list) { diff --git a/qtest.c b/qtest.c index 1446719e8d..a6858272eb 100644 --- a/qtest.c +++ b/qtest.c @@ -373,8 +373,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) uint64_t value; g_assert(words[1] && words[2]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &value) == 0); if (words[0][5] == 'b') { uint8_t data = value; @@ -402,7 +402,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) uint64_t value = UINT64_C(-1); g_assert(words[1]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); if (words[0][4] == 'b') { uint8_t data; @@ -428,8 +428,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) char *enc; g_assert(words[1] && words[2]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0); /* We'd send garbage to libqtest if len is 0 */ g_assert(len); @@ -452,8 +452,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) gchar *b64_data; g_assert(words[1] && words[2]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -469,8 +469,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) size_t data_len; g_assert(words[1] && words[2] && words[3]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -498,8 +498,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) unsigned long pattern; g_assert(words[1] && words[2] && words[3]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0); g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0); if (len) { @@ -518,8 +518,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words) gsize out_len; g_assert(words[1] && words[2] && words[3]); - g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); - g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -552,9 +552,9 @@ static void qtest_process_command(CharBackend *chr, gchar **words) unsigned long nargs, nret; g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0); - g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0); + g_assert(qemu_strtou64(words[3], NULL, 0, &args) == 0); g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0); - g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0); + g_assert(qemu_strtou64(words[5], NULL, 0, &ret) == 0); res = qtest_rtas_call(words[1], nargs, args, nret, ret); qtest_send_prefix(chr); @@ -564,7 +564,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) int64_t ns; if (words[1]) { - g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); + g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0); } else { ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); } @@ -576,7 +576,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) int64_t ns; g_assert(words[1]); - g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); + g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0); qtest_clock_warp(ns); qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 749aaa938a..185b0233f2 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -796,7 +796,7 @@ static void test_qemu_strtoul_full_max(void) g_free(str); } -static void test_qemu_strtoll_correct(void) +static void test_qemu_strtoi64_correct(void) { const char *str = "12345 foo"; char f = 'X'; @@ -804,27 +804,27 @@ static void test_qemu_strtoll_correct(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); g_assert(endptr == str + 5); } -static void test_qemu_strtoll_null(void) +static void test_qemu_strtoi64_null(void) { char f = 'X'; const char *endptr = &f; int64_t res = 999; int err; - err = qemu_strtoll(NULL, &endptr, 0, &res); + err = qemu_strtoi64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == NULL); } -static void test_qemu_strtoll_empty(void) +static void test_qemu_strtoi64_empty(void) { const char *str = ""; char f = 'X'; @@ -832,13 +832,13 @@ static void test_qemu_strtoll_empty(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoll_whitespace(void) +static void test_qemu_strtoi64_whitespace(void) { const char *str = " \t "; char f = 'X'; @@ -846,13 +846,13 @@ static void test_qemu_strtoll_whitespace(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoll_invalid(void) +static void test_qemu_strtoi64_invalid(void) { const char *str = " xxxx \t abc"; char f = 'X'; @@ -860,13 +860,13 @@ static void test_qemu_strtoll_invalid(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoll_trailing(void) +static void test_qemu_strtoi64_trailing(void) { const char *str = "123xxx"; char f = 'X'; @@ -874,14 +874,14 @@ static void test_qemu_strtoll_trailing(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); g_assert(endptr == str + 3); } -static void test_qemu_strtoll_octal(void) +static void test_qemu_strtoi64_octal(void) { const char *str = "0123"; char f = 'X'; @@ -889,7 +889,7 @@ static void test_qemu_strtoll_octal(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 8, &res); + err = qemu_strtoi64(str, &endptr, 8, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); @@ -897,14 +897,14 @@ static void test_qemu_strtoll_octal(void) endptr = &f; res = 999; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_decimal(void) +static void test_qemu_strtoi64_decimal(void) { const char *str = "0123"; char f = 'X'; @@ -912,7 +912,7 @@ static void test_qemu_strtoll_decimal(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 10, &res); + err = qemu_strtoi64(str, &endptr, 10, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); @@ -921,14 +921,14 @@ static void test_qemu_strtoll_decimal(void) str = "123"; endptr = &f; res = 999; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_hex(void) +static void test_qemu_strtoi64_hex(void) { const char *str = "0123"; char f = 'X'; @@ -936,7 +936,7 @@ static void test_qemu_strtoll_hex(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 16, &res); + err = qemu_strtoi64(str, &endptr, 16, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); @@ -945,14 +945,14 @@ static void test_qemu_strtoll_hex(void) str = "0x123"; endptr = &f; res = 999; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_max(void) +static void test_qemu_strtoi64_max(void) { char *str = g_strdup_printf("%lld", LLONG_MAX); char f = 'X'; @@ -960,7 +960,7 @@ static void test_qemu_strtoll_max(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LLONG_MAX); @@ -968,7 +968,7 @@ static void test_qemu_strtoll_max(void) g_free(str); } -static void test_qemu_strtoll_overflow(void) +static void test_qemu_strtoi64_overflow(void) { const char *str = "99999999999999999999999999999999999999999999"; char f = 'X'; @@ -976,14 +976,14 @@ static void test_qemu_strtoll_overflow(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LLONG_MAX); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_underflow(void) +static void test_qemu_strtoi64_underflow(void) { const char *str = "-99999999999999999999999999999999999999999999"; char f = 'X'; @@ -991,14 +991,14 @@ static void test_qemu_strtoll_underflow(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmpint(res, ==, LLONG_MIN); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_negative(void) +static void test_qemu_strtoi64_negative(void) { const char *str = " \t -321"; char f = 'X'; @@ -1006,84 +1006,84 @@ static void test_qemu_strtoll_negative(void) int64_t res = 999; int err; - err = qemu_strtoll(str, &endptr, 0, &res); + err = qemu_strtoi64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, -321); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoll_full_correct(void) +static void test_qemu_strtoi64_full_correct(void) { const char *str = "123"; int64_t res = 999; int err; - err = qemu_strtoll(str, NULL, 0, &res); + err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 123); } -static void test_qemu_strtoll_full_null(void) +static void test_qemu_strtoi64_full_null(void) { int64_t res = 999; int err; - err = qemu_strtoll(NULL, NULL, 0, &res); + err = qemu_strtoi64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoll_full_empty(void) +static void test_qemu_strtoi64_full_empty(void) { const char *str = ""; int64_t res = 999; int err; - err = qemu_strtoll(str, NULL, 0, &res); + err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoll_full_negative(void) +static void test_qemu_strtoi64_full_negative(void) { const char *str = " \t -321"; int64_t res = 999; int err; - err = qemu_strtoll(str, NULL, 0, &res); + err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, -321); } -static void test_qemu_strtoll_full_trailing(void) +static void test_qemu_strtoi64_full_trailing(void) { const char *str = "123xxx"; int64_t res = 999; int err; - err = qemu_strtoll(str, NULL, 0, &res); + err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoll_full_max(void) +static void test_qemu_strtoi64_full_max(void) { char *str = g_strdup_printf("%lld", LLONG_MAX); int64_t res; int err; - err = qemu_strtoll(str, NULL, 0, &res); + err = qemu_strtoi64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LLONG_MAX); g_free(str); } -static void test_qemu_strtoull_correct(void) +static void test_qemu_strtou64_correct(void) { const char *str = "12345 foo"; char f = 'X'; @@ -1091,27 +1091,27 @@ static void test_qemu_strtoull_correct(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 12345); g_assert(endptr == str + 5); } -static void test_qemu_strtoull_null(void) +static void test_qemu_strtou64_null(void) { char f = 'X'; const char *endptr = &f; uint64_t res = 999; int err; - err = qemu_strtoull(NULL, &endptr, 0, &res); + err = qemu_strtou64(NULL, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == NULL); } -static void test_qemu_strtoull_empty(void) +static void test_qemu_strtou64_empty(void) { const char *str = ""; char f = 'X'; @@ -1119,13 +1119,13 @@ static void test_qemu_strtoull_empty(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoull_whitespace(void) +static void test_qemu_strtou64_whitespace(void) { const char *str = " \t "; char f = 'X'; @@ -1133,13 +1133,13 @@ static void test_qemu_strtoull_whitespace(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoull_invalid(void) +static void test_qemu_strtou64_invalid(void) { const char *str = " xxxx \t abc"; char f = 'X'; @@ -1147,13 +1147,13 @@ static void test_qemu_strtoull_invalid(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } -static void test_qemu_strtoull_trailing(void) +static void test_qemu_strtou64_trailing(void) { const char *str = "123xxx"; char f = 'X'; @@ -1161,14 +1161,14 @@ static void test_qemu_strtoull_trailing(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + 3); } -static void test_qemu_strtoull_octal(void) +static void test_qemu_strtou64_octal(void) { const char *str = "0123"; char f = 'X'; @@ -1176,7 +1176,7 @@ static void test_qemu_strtoull_octal(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 8, &res); + err = qemu_strtou64(str, &endptr, 8, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); @@ -1184,14 +1184,14 @@ static void test_qemu_strtoull_octal(void) endptr = &f; res = 999; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 0123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_decimal(void) +static void test_qemu_strtou64_decimal(void) { const char *str = "0123"; char f = 'X'; @@ -1199,7 +1199,7 @@ static void test_qemu_strtoull_decimal(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 10, &res); + err = qemu_strtou64(str, &endptr, 10, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); @@ -1208,14 +1208,14 @@ static void test_qemu_strtoull_decimal(void) str = "123"; endptr = &f; res = 999; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_hex(void) +static void test_qemu_strtou64_hex(void) { const char *str = "0123"; char f = 'X'; @@ -1223,7 +1223,7 @@ static void test_qemu_strtoull_hex(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 16, &res); + err = qemu_strtou64(str, &endptr, 16, &res); g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); @@ -1232,14 +1232,14 @@ static void test_qemu_strtoull_hex(void) str = "0x123"; endptr = &f; res = 999; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, 0x123); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_max(void) +static void test_qemu_strtou64_max(void) { char *str = g_strdup_printf("%llu", ULLONG_MAX); char f = 'X'; @@ -1247,7 +1247,7 @@ static void test_qemu_strtoull_max(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, ULLONG_MAX); @@ -1255,7 +1255,7 @@ static void test_qemu_strtoull_max(void) g_free(str); } -static void test_qemu_strtoull_overflow(void) +static void test_qemu_strtou64_overflow(void) { const char *str = "99999999999999999999999999999999999999999999"; char f = 'X'; @@ -1263,14 +1263,14 @@ static void test_qemu_strtoull_overflow(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, ULLONG_MAX); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_underflow(void) +static void test_qemu_strtou64_underflow(void) { const char *str = "-99999999999999999999999999999999999999999999"; char f = 'X'; @@ -1278,14 +1278,14 @@ static void test_qemu_strtoull_underflow(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert_cmphex(res, ==, -1ull); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_negative(void) +static void test_qemu_strtou64_negative(void) { const char *str = " \t -321"; char f = 'X'; @@ -1293,76 +1293,76 @@ static void test_qemu_strtoull_negative(void) uint64_t res = 999; int err; - err = qemu_strtoull(str, &endptr, 0, &res); + err = qemu_strtou64(str, &endptr, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, -321ull); g_assert(endptr == str + strlen(str)); } -static void test_qemu_strtoull_full_correct(void) +static void test_qemu_strtou64_full_correct(void) { const char *str = "18446744073709551614"; uint64_t res = 999; int err; - err = qemu_strtoull(str, NULL, 0, &res); + err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, 18446744073709551614ull); } -static void test_qemu_strtoull_full_null(void) +static void test_qemu_strtou64_full_null(void) { uint64_t res = 999; int err; - err = qemu_strtoull(NULL, NULL, 0, &res); + err = qemu_strtou64(NULL, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoull_full_empty(void) +static void test_qemu_strtou64_full_empty(void) { const char *str = ""; uint64_t res = 999; int err; - err = qemu_strtoull(str, NULL, 0, &res); + err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoull_full_negative(void) +static void test_qemu_strtou64_full_negative(void) { const char *str = " \t -321"; uint64_t res = 999; int err; - err = qemu_strtoull(str, NULL, 0, &res); + err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmpuint(res, ==, -321ull); } -static void test_qemu_strtoull_full_trailing(void) +static void test_qemu_strtou64_full_trailing(void) { const char *str = "18446744073709551614xxxxxx"; uint64_t res = 999; int err; - err = qemu_strtoull(str, NULL, 0, &res); + err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, -EINVAL); } -static void test_qemu_strtoull_full_max(void) +static void test_qemu_strtou64_full_max(void) { char *str = g_strdup_printf("%lld", ULLONG_MAX); uint64_t res = 999; int err; - err = qemu_strtoull(str, NULL, 0, &res); + err = qemu_strtou64(str, NULL, 0, &res); g_assert_cmpint(err, ==, 0); g_assert_cmphex(res, ==, ULLONG_MAX); @@ -1471,21 +1471,32 @@ int main(int argc, char **argv) test_parse_uint_full_correct); /* qemu_strtol() tests */ - 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); + 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); g_test_add_func("/cutils/qemu_strtol/whitespace", test_qemu_strtol_whitespace); - 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); + 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); g_test_add_func("/cutils/qemu_strtol/underflow", test_qemu_strtol_underflow); - g_test_add_func("/cutils/qemu_strtol/negative", test_qemu_strtol_negative); + g_test_add_func("/cutils/qemu_strtol/negative", + test_qemu_strtol_negative); g_test_add_func("/cutils/qemu_strtol_full/correct", test_qemu_strtol_full_correct); g_test_add_func("/cutils/qemu_strtol_full/null", @@ -1500,18 +1511,26 @@ int main(int argc, char **argv) test_qemu_strtol_full_max); /* qemu_strtoul() tests */ - 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); + 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); g_test_add_func("/cutils/qemu_strtoul/whitespace", test_qemu_strtoul_whitespace); - g_test_add_func("/cutils/qemu_strtoul/invalid", test_qemu_strtoul_invalid); + g_test_add_func("/cutils/qemu_strtoul/invalid", + test_qemu_strtoul_invalid); g_test_add_func("/cutils/qemu_strtoul/trailing", test_qemu_strtoul_trailing); - 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); - g_test_add_func("/cutils/qemu_strtoul/max", test_qemu_strtoul_max); + 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); + g_test_add_func("/cutils/qemu_strtoul/max", + test_qemu_strtoul_max); g_test_add_func("/cutils/qemu_strtoul/overflow", test_qemu_strtoul_overflow); g_test_add_func("/cutils/qemu_strtoul/underflow", @@ -1531,73 +1550,86 @@ int main(int argc, char **argv) g_test_add_func("/cutils/qemu_strtoul_full/max", test_qemu_strtoul_full_max); - /* qemu_strtoll() tests */ - g_test_add_func("/cutils/qemu_strtoll/correct", test_qemu_strtoll_correct); - g_test_add_func("/cutils/qemu_strtoll/null", test_qemu_strtoll_null); - g_test_add_func("/cutils/qemu_strtoll/empty", test_qemu_strtoll_empty); - g_test_add_func("/cutils/qemu_strtoll/whitespace", - test_qemu_strtoll_whitespace); - g_test_add_func("/cutils/qemu_strtoll/invalid", test_qemu_strtoll_invalid); - g_test_add_func("/cutils/qemu_strtoll/trailing", - test_qemu_strtoll_trailing); - g_test_add_func("/cutils/qemu_strtoll/octal", test_qemu_strtoll_octal); - g_test_add_func("/cutils/qemu_strtoll/decimal", test_qemu_strtoll_decimal); - g_test_add_func("/cutils/qemu_strtoll/hex", test_qemu_strtoll_hex); - g_test_add_func("/cutils/qemu_strtoll/max", test_qemu_strtoll_max); - g_test_add_func("/cutils/qemu_strtoll/overflow", - test_qemu_strtoll_overflow); - g_test_add_func("/cutils/qemu_strtoll/underflow", - test_qemu_strtoll_underflow); - g_test_add_func("/cutils/qemu_strtoll/negative", - test_qemu_strtoll_negative); - g_test_add_func("/cutils/qemu_strtoll_full/correct", - test_qemu_strtoll_full_correct); - g_test_add_func("/cutils/qemu_strtoll_full/null", - test_qemu_strtoll_full_null); - g_test_add_func("/cutils/qemu_strtoll_full/empty", - test_qemu_strtoll_full_empty); - g_test_add_func("/cutils/qemu_strtoll_full/negative", - test_qemu_strtoll_full_negative); - g_test_add_func("/cutils/qemu_strtoll_full/trailing", - test_qemu_strtoll_full_trailing); - g_test_add_func("/cutils/qemu_strtoll_full/max", - test_qemu_strtoll_full_max); + /* 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); + g_test_add_func("/cutils/qemu_strtoi64/invalid" + , + 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); + g_test_add_func("/cutils/qemu_strtoi64/underflow", + test_qemu_strtoi64_underflow); + g_test_add_func("/cutils/qemu_strtoi64/negative", + test_qemu_strtoi64_negative); + 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); + 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); - /* qemu_strtoull() tests */ - g_test_add_func("/cutils/qemu_strtoull/correct", - test_qemu_strtoull_correct); - g_test_add_func("/cutils/qemu_strtoull/null", - test_qemu_strtoull_null); - g_test_add_func("/cutils/qemu_strtoull/empty", test_qemu_strtoull_empty); - g_test_add_func("/cutils/qemu_strtoull/whitespace", - test_qemu_strtoull_whitespace); - g_test_add_func("/cutils/qemu_strtoull/invalid", - test_qemu_strtoull_invalid); - g_test_add_func("/cutils/qemu_strtoull/trailing", - test_qemu_strtoull_trailing); - g_test_add_func("/cutils/qemu_strtoull/octal", test_qemu_strtoull_octal); - g_test_add_func("/cutils/qemu_strtoull/decimal", - test_qemu_strtoull_decimal); - g_test_add_func("/cutils/qemu_strtoull/hex", test_qemu_strtoull_hex); - g_test_add_func("/cutils/qemu_strtoull/max", test_qemu_strtoull_max); - g_test_add_func("/cutils/qemu_strtoull/overflow", - test_qemu_strtoull_overflow); - g_test_add_func("/cutils/qemu_strtoull/underflow", - test_qemu_strtoull_underflow); - g_test_add_func("/cutils/qemu_strtoull/negative", - test_qemu_strtoull_negative); - g_test_add_func("/cutils/qemu_strtoull_full/correct", - test_qemu_strtoull_full_correct); - g_test_add_func("/cutils/qemu_strtoull_full/null", - test_qemu_strtoull_full_null); - g_test_add_func("/cutils/qemu_strtoull_full/empty", - test_qemu_strtoull_full_empty); - g_test_add_func("/cutils/qemu_strtoull_full/negative", - test_qemu_strtoull_full_negative); - g_test_add_func("/cutils/qemu_strtoull_full/trailing", - test_qemu_strtoull_full_trailing); - g_test_add_func("/cutils/qemu_strtoull_full/max", - test_qemu_strtoull_full_max); + /* 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); + 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); + 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); + 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); g_test_add_func("/cutils/strtosz/simple", test_qemu_strtosz_simple); diff --git a/util/cutils.c b/util/cutils.c index 1ae2a0814b..0dc9b28298 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -372,7 +372,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, * Works like qemu_strtol(), except it stores INT64_MAX on overflow, * and INT_MIN on underflow. */ -int qemu_strtoll(const char *nptr, const char **endptr, int base, +int qemu_strtoi64(const char *nptr, const char **endptr, int base, int64_t *result) { char *p; @@ -396,7 +396,7 @@ int qemu_strtoll(const char *nptr, const char **endptr, int base, * * Works like qemu_strtoul(), except it stores UINT64_MAX on overflow. */ -int qemu_strtoull(const char *nptr, const char **endptr, int base, +int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result) { char *p; diff --git a/util/log.c b/util/log.c index e077340ae1..96f30dd21a 100644 --- a/util/log.c +++ b/util/log.c @@ -183,13 +183,13 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp) goto out; } - if (qemu_strtoull(r, &e, 0, &r1val) + if (qemu_strtou64(r, &e, 0, &r1val) || e != range_op) { error_setg(errp, "Invalid number to the left of %.*s", (int)(r2 - range_op), range_op); goto out; } - if (qemu_strtoull(r2, NULL, 0, &r2val)) { + if (qemu_strtou64(r2, NULL, 0, &r2val)) { error_setg(errp, "Invalid number to the right of %.*s", (int)(r2 - range_op), range_op); goto out; From 717adf960933da0650d995f050d457063d591914 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:51 +0100 Subject: [PATCH 07/24] util/cutils: Clean up variable names around qemu_strtol() Name same things the same, different things differently. * qemu_strtol()'s parameter @nptr is called @p in check_strtox_error(). Rename the latter. * qemu_strtol()'s parameter @endptr is called @next in check_strtox_error(). Rename the latter. * qemu_strtol()'s variable @p is called @endptr in check_strtox_error(). Rename both to @ep. * qemu_strtol()'s variable @err is *negative* errno, check_strtox_error()'s parameter @err is *positive*. Rename the latter to @libc_errno. Same for qemu_strtoul(), qemu_strtoi64(), qemu_strtou64(), of course. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-8-git-send-email-armbru@redhat.com> --- util/cutils.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 0dc9b28298..0fb0f82289 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -260,21 +260,21 @@ int64_t qemu_strtosz(const char *nptr, char **end) } /** - * Helper function for qemu_strto*l() functions. + * Helper function for error checking after strtol() and the like */ -static int check_strtox_error(const char *p, char *endptr, const char **next, - int err) +static int check_strtox_error(const char *nptr, char *ep, + const char **endptr, int libc_errno) { - if (err == 0 && endptr == p) { - err = EINVAL; + if (libc_errno == 0 && ep == nptr) { + libc_errno = EINVAL; } - if (!next && *endptr) { + if (!endptr && *ep) { return -EINVAL; } - if (next) { - *next = endptr; + if (endptr) { + *endptr = ep; } - return -err; + return -libc_errno; } /** @@ -304,7 +304,7 @@ static int check_strtox_error(const char *p, char *endptr, const char **next, int qemu_strtol(const char *nptr, const char **endptr, int base, long *result) { - char *p; + char *ep; int err = 0; if (!nptr) { if (endptr) { @@ -313,8 +313,8 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, err = -EINVAL; } else { errno = 0; - *result = strtol(nptr, &p, base); - err = check_strtox_error(nptr, p, endptr, errno); + *result = strtol(nptr, &ep, base); + err = check_strtox_error(nptr, ep, endptr, errno); } return err; } @@ -347,7 +347,7 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result) { - char *p; + char *ep; int err = 0; if (!nptr) { if (endptr) { @@ -356,12 +356,12 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, err = -EINVAL; } else { errno = 0; - *result = strtoul(nptr, &p, base); + *result = strtoul(nptr, &ep, base); /* Windows returns 1 for negative out-of-range values. */ if (errno == ERANGE) { *result = -1; } - err = check_strtox_error(nptr, p, endptr, errno); + err = check_strtox_error(nptr, ep, endptr, errno); } return err; } @@ -375,7 +375,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, int qemu_strtoi64(const char *nptr, const char **endptr, int base, int64_t *result) { - char *p; + char *ep; int err = 0; if (!nptr) { if (endptr) { @@ -385,8 +385,8 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, } else { errno = 0; /* FIXME This assumes int64_t is long long */ - *result = strtoll(nptr, &p, base); - err = check_strtox_error(nptr, p, endptr, errno); + *result = strtoll(nptr, &ep, base); + err = check_strtox_error(nptr, ep, endptr, errno); } return err; } @@ -399,7 +399,7 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result) { - char *p; + char *ep; int err = 0; if (!nptr) { if (endptr) { @@ -409,12 +409,12 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, } else { errno = 0; /* FIXME This assumes uint64_t is unsigned long long */ - *result = strtoull(nptr, &p, base); + *result = strtoull(nptr, &ep, base); /* Windows returns 1 for negative out-of-range values. */ if (errno == ERANGE) { *result = -1; } - err = check_strtox_error(nptr, p, endptr, errno); + err = check_strtox_error(nptr, ep, endptr, errno); } return err; } From 4baef2679e029c76707be1e2ed54bf3dd21693fe Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:52 +0100 Subject: [PATCH 08/24] util/cutils: Clean up control flow around qemu_strtol() a bit Reorder check_strtox_error() to make it obvious that we always store through a non-null @endptr. Transform if (some error) { error case ... err = value for error case; } else { normal case ... err = value for normal case; } return err; to if (some error) { error case ... return value for error case; } normal case ... return value for normal case; Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-9-git-send-email-armbru@redhat.com> --- util/cutils.c | 89 ++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 0fb0f82289..6397424111 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -265,15 +265,20 @@ int64_t qemu_strtosz(const char *nptr, char **end) static int check_strtox_error(const char *nptr, char *ep, const char **endptr, int libc_errno) { - if (libc_errno == 0 && ep == nptr) { - libc_errno = EINVAL; - } - if (!endptr && *ep) { - return -EINVAL; - } if (endptr) { *endptr = ep; } + + /* Turn "no conversion" into an error */ + if (libc_errno == 0 && ep == nptr) { + return -EINVAL; + } + + /* Fail when we're expected to consume the string, but didn't */ + if (!endptr && *ep) { + return -EINVAL; + } + return -libc_errno; } @@ -305,18 +310,17 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, long *result) { char *ep; - int err = 0; + if (!nptr) { if (endptr) { *endptr = nptr; } - err = -EINVAL; - } else { - errno = 0; - *result = strtol(nptr, &ep, base); - err = check_strtox_error(nptr, ep, endptr, errno); + return -EINVAL; } - return err; + + errno = 0; + *result = strtol(nptr, &ep, base); + return check_strtox_error(nptr, ep, endptr, errno); } /** @@ -348,22 +352,21 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result) { char *ep; - int err = 0; + if (!nptr) { if (endptr) { *endptr = nptr; } - err = -EINVAL; - } else { - errno = 0; - *result = strtoul(nptr, &ep, base); - /* Windows returns 1 for negative out-of-range values. */ - if (errno == ERANGE) { - *result = -1; - } - err = check_strtox_error(nptr, ep, endptr, errno); + return -EINVAL; } - return err; + + errno = 0; + *result = strtoul(nptr, &ep, base); + /* Windows returns 1 for negative out-of-range values. */ + if (errno == ERANGE) { + *result = -1; + } + return check_strtox_error(nptr, ep, endptr, errno); } /** @@ -376,19 +379,18 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, int64_t *result) { char *ep; - int err = 0; + if (!nptr) { if (endptr) { *endptr = nptr; } - err = -EINVAL; - } else { - errno = 0; - /* FIXME This assumes int64_t is long long */ - *result = strtoll(nptr, &ep, base); - err = check_strtox_error(nptr, ep, endptr, errno); + return -EINVAL; } - return err; + + errno = 0; + /* FIXME This assumes int64_t is long long */ + *result = strtoll(nptr, &ep, base); + return check_strtox_error(nptr, ep, endptr, errno); } /** @@ -400,23 +402,22 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result) { char *ep; - int err = 0; + if (!nptr) { if (endptr) { *endptr = nptr; } - err = -EINVAL; - } else { - errno = 0; - /* FIXME This assumes uint64_t is unsigned long long */ - *result = strtoull(nptr, &ep, base); - /* Windows returns 1 for negative out-of-range values. */ - if (errno == ERANGE) { - *result = -1; - } - err = check_strtox_error(nptr, ep, endptr, errno); + return -EINVAL; } - return err; + + errno = 0; + /* FIXME This assumes uint64_t is unsigned long long */ + *result = strtoull(nptr, &ep, base); + /* Windows returns 1 for negative out-of-range values. */ + if (errno == ERANGE) { + *result = -1; + } + return check_strtox_error(nptr, ep, endptr, errno); } /** From 3403e5eb884f3a74c40fe7cccc103f848c040215 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:53 +0100 Subject: [PATCH 09/24] option: Fix to reject invalid and overflowing numbers parse_option_number() fails to check for these errors after strtoull(). Has always been broken. Fix that. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-10-git-send-email-armbru@redhat.com> --- tests/test-qemu-opts.c | 19 ++++++++----------- util/qemu-option.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 310485bb2e..8b92f7b0dc 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -603,17 +603,15 @@ static void test_opts_parse_number(void) /* Above upper limit */ opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616", - false, &error_abort); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); + false, &err); + error_free_or_abort(&err); + g_assert(!opts); /* Below lower limit */ opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616", - false, &error_abort); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX); + false, &err); + error_free_or_abort(&err); + g_assert(!opts); /* Hex and octal */ opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052", @@ -624,9 +622,8 @@ static void test_opts_parse_number(void) /* Invalid */ opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0); + error_free_or_abort(&err); + g_assert(!opts); opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err); error_free_or_abort(&err); g_assert(!opts); diff --git a/util/qemu-option.c b/util/qemu-option.c index 9708668847..273d00d485 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -141,11 +141,16 @@ static void parse_option_bool(const char *name, const char *value, bool *ret, static void parse_option_number(const char *name, const char *value, uint64_t *ret, Error **errp) { - char *postfix; uint64_t number; + int err; - number = strtoull(value, &postfix, 0); - if (*postfix != '\0') { + err = qemu_strtou64(value, NULL, 0, &number); + if (err == -ERANGE) { + error_setg(errp, "Value '%s' is too large for parameter '%s'", + value, name); + return; + } + if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); return; } From 019144b2866f38884fe9996d8738c50e680e3bfa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:54 +0100 Subject: [PATCH 10/24] test-cutils: Add missing qemu_strtosz()... endptr checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1487708048-2131-11-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 185b0233f2..a3eb18273f 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1393,60 +1393,75 @@ static void test_qemu_strtosz_units(void) const char *t = "1T"; const char *p = "1P"; const char *e = "1E"; + char *endptr = NULL; int64_t res; /* default is M */ - res = qemu_strtosz(none, NULL); + res = qemu_strtosz(none, &endptr); g_assert_cmpint(res, ==, M_BYTE); + g_assert(endptr == none + 1); - res = qemu_strtosz(b, NULL); + res = qemu_strtosz(b, &endptr); g_assert_cmpint(res, ==, 1); + g_assert(endptr == b + 2); - res = qemu_strtosz(k, NULL); + res = qemu_strtosz(k, &endptr); g_assert_cmpint(res, ==, K_BYTE); + g_assert(endptr == k + 2); - res = qemu_strtosz(m, NULL); + res = qemu_strtosz(m, &endptr); g_assert_cmpint(res, ==, M_BYTE); + g_assert(endptr == m + 2); - res = qemu_strtosz(g, NULL); + res = qemu_strtosz(g, &endptr); g_assert_cmpint(res, ==, G_BYTE); + g_assert(endptr == g + 2); - res = qemu_strtosz(t, NULL); + res = qemu_strtosz(t, &endptr); g_assert_cmpint(res, ==, T_BYTE); + g_assert(endptr == t + 2); - res = qemu_strtosz(p, NULL); + res = qemu_strtosz(p, &endptr); g_assert_cmpint(res, ==, P_BYTE); + g_assert(endptr == p + 2); - res = qemu_strtosz(e, NULL); + res = qemu_strtosz(e, &endptr); g_assert_cmpint(res, ==, E_BYTE); + g_assert(endptr == e + 2); } static void test_qemu_strtosz_float(void) { const char *str = "12.345M"; + char *endptr = NULL; int64_t res; - res = qemu_strtosz(str, NULL); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 12.345 * M_BYTE); + g_assert(endptr == str + 7); } static void test_qemu_strtosz_erange(void) { const char *str = "10E"; + char *endptr = NULL; int64_t res; - res = qemu_strtosz(str, NULL); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); + g_assert(endptr == str + 3); } static void test_qemu_strtosz_suffix_unit(void) { const char *str = "12345"; + char *endptr = NULL; int64_t res; - res = qemu_strtosz_suffix_unit(str, NULL, + res = qemu_strtosz_suffix_unit(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_KB, 1000); g_assert_cmpint(res, ==, 12345000); + g_assert(endptr == str + 5); } int main(int argc, char **argv) From 18aec47967814f4a6261edd0130f7e9da985f65b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:55 +0100 Subject: [PATCH 11/24] test-cutils: Cover qemu_strtosz() invalid input Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-12-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index a3eb18273f..dc8cd8d02d 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1441,6 +1441,28 @@ static void test_qemu_strtosz_float(void) g_assert(endptr == str + 7); } +static void test_qemu_strtosz_invalid(void) +{ + const char *str; + char *endptr = NULL; + int64_t res; + + str = ""; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, -EINVAL); + g_assert(endptr == str); + + str = " \t "; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, -EINVAL); + g_assert(endptr == str); + + str = "crap"; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, -EINVAL); + g_assert(endptr == str); +} + static void test_qemu_strtosz_erange(void) { const char *str = "10E"; @@ -1652,6 +1674,8 @@ int main(int argc, char **argv) test_qemu_strtosz_units); g_test_add_func("/cutils/strtosz/float", test_qemu_strtosz_float); + g_test_add_func("/cutils/strtosz/invalid", + test_qemu_strtosz_invalid); g_test_add_func("/cutils/strtosz/erange", test_qemu_strtosz_erange); g_test_add_func("/cutils/strtosz/suffix-unit", From a6b4373fa257fdd7139a74187851575709a5ecb6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:56 +0100 Subject: [PATCH 12/24] test-cutils: Cover qemu_strtosz() with trailing crap Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-13-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index dc8cd8d02d..1773f15a64 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1463,6 +1463,23 @@ static void test_qemu_strtosz_invalid(void) g_assert(endptr == str); } +static void test_qemu_strtosz_trailing(void) +{ + const char *str; + char *endptr = NULL; + int64_t res; + + str = "123xxx"; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, 123 * M_BYTE); + g_assert(endptr == str + 3); + + str = "1kiB"; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, 1024); + g_assert(endptr == str + 2); +} + static void test_qemu_strtosz_erange(void) { const char *str = "10E"; @@ -1676,6 +1693,8 @@ int main(int argc, char **argv) test_qemu_strtosz_float); g_test_add_func("/cutils/strtosz/invalid", test_qemu_strtosz_invalid); + g_test_add_func("/cutils/strtosz/trailing", + test_qemu_strtosz_trailing); g_test_add_func("/cutils/strtosz/erange", test_qemu_strtosz_erange); g_test_add_func("/cutils/strtosz/suffix-unit", From 0b742797aaada3a2e243175a69d542d2ed997aac Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:57 +0100 Subject: [PATCH 13/24] test-cutils: Cover qemu_strtosz() around range limits Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-14-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 61 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 1773f15a64..df6c3308ea 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1371,16 +1371,52 @@ static void test_qemu_strtou64_full_max(void) static void test_qemu_strtosz_simple(void) { - const char *str = "12345M"; + const char *str; char *endptr = NULL; int64_t res; + str = "0"; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str + 1); + + str = "12345M"; res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 12345 * M_BYTE); g_assert(endptr == str + 6); res = qemu_strtosz(str, NULL); g_assert_cmpint(res, ==, 12345 * M_BYTE); + + /* Note: precision is 53 bits since we're parsing with strtod() */ + + str = "9007199254740991"; /* 2^53-1 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, 0x1fffffffffffff); + g_assert(endptr == str + 16); + + str = "9007199254740992"; /* 2^53 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, 0x20000000000000); + g_assert(endptr == str + 16); + + str = "9007199254740993"; /* 2^53+1 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, 0x20000000000000); /* rounded to 53 bits */ + g_assert(endptr == str + 16); + + str = "9223372036854774784"; /* 0x7ffffffffffffc00 (53 msbs set) */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, 0x7ffffffffffffc00); + g_assert(endptr == str + 19); + + str = "9223372036854775295"; /* 0x7ffffffffffffdff */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, 0x7ffffffffffffc00); /* rounded to 53 bits */ + g_assert(endptr == str + 19); + + /* 0x7ffffffffffffe00..0x7fffffffffffffff get rounded to + * 0x8000000000000000, thus -ERANGE; see test_qemu_strtosz_erange() */ } static void test_qemu_strtosz_units(void) @@ -1482,10 +1518,31 @@ static void test_qemu_strtosz_trailing(void) static void test_qemu_strtosz_erange(void) { - const char *str = "10E"; + const char *str; char *endptr = NULL; int64_t res; + str = "-1"; + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, -ERANGE); + g_assert(endptr == str + 2); + + str = "9223372036854775296"; /* 0x7ffffffffffffe00 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, -ERANGE); + g_assert(endptr == str + 19); + + str = "9223372036854775807"; /* 2^63-1 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, -ERANGE); + g_assert(endptr == str + 19); + + str = "9223372036854775808"; /* 2^63 */ + res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + g_assert_cmpint(res, ==, -ERANGE); + g_assert(endptr == str + 19); + + str = "10E"; res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 3); From d2734d2629266006b0413433778474d5801c60be Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:58 +0100 Subject: [PATCH 14/24] util/cutils: New qemu_strtosz_metric() To parse numbers with metric suffixes, we use qemu_strtosz_suffix_unit(nptr, &eptr, QEMU_STRTOSZ_DEFSUFFIX_B, 1000) Capture this in a new function for legibility: qemu_strtosz_metric(nptr, &eptr) Replace test_qemu_strtosz_suffix_unit() by test_qemu_strtosz_metric(). Rename qemu_strtosz_suffix_unit() to do_strtosz() and give it internal linkage. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-15-git-send-email-armbru@redhat.com> --- include/qemu/cutils.h | 4 ++-- target/i386/cpu.c | 3 +-- tests/test-cutils.c | 13 ++++++------- util/cutils.c | 11 ++++++++--- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index f922223f04..81613d01ee 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -156,8 +156,8 @@ int parse_uint_full(const char *s, unsigned long long *value, int base); int64_t qemu_strtosz(const char *nptr, char **end); int64_t qemu_strtosz_suffix(const char *nptr, char **end, const char default_suffix); -int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end, - const char default_suffix, int64_t unit); +int64_t qemu_strtosz_metric(const char *nptr, char **end); + #define K_BYTE (1ULL << 10) #define M_BYTE (1ULL << 20) #define G_BYTE (1ULL << 30) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fd7add2521..685ca36640 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2036,8 +2036,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, int64_t tsc_freq; char *err; - tsc_freq = qemu_strtosz_suffix_unit(val, &err, - QEMU_STRTOSZ_DEFSUFFIX_B, 1000); + tsc_freq = qemu_strtosz_metric(val, &err); if (tsc_freq < 0 || *err) { error_setg(errp, "bad numerical value %s", val); return; diff --git a/tests/test-cutils.c b/tests/test-cutils.c index df6c3308ea..e1d40548c0 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1548,16 +1548,15 @@ static void test_qemu_strtosz_erange(void) g_assert(endptr == str + 3); } -static void test_qemu_strtosz_suffix_unit(void) +static void test_qemu_strtosz_metric(void) { - const char *str = "12345"; + const char *str = "12345k"; char *endptr = NULL; int64_t res; - res = qemu_strtosz_suffix_unit(str, &endptr, - QEMU_STRTOSZ_DEFSUFFIX_KB, 1000); + res = qemu_strtosz_metric(str, &endptr); g_assert_cmpint(res, ==, 12345000); - g_assert(endptr == str + 5); + g_assert(endptr == str + 6); } int main(int argc, char **argv) @@ -1754,8 +1753,8 @@ int main(int argc, char **argv) test_qemu_strtosz_trailing); g_test_add_func("/cutils/strtosz/erange", test_qemu_strtosz_erange); - g_test_add_func("/cutils/strtosz/suffix-unit", - test_qemu_strtosz_suffix_unit); + g_test_add_func("/cutils/strtosz/metric", + test_qemu_strtosz_metric); return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 6397424111..b46e254f83 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -205,8 +205,8 @@ static int64_t suffix_mul(char suffix, int64_t unit) * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on * other error. */ -int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end, - const char default_suffix, int64_t unit) +static int64_t do_strtosz(const char *nptr, char **end, + const char default_suffix, int64_t unit) { int64_t retval = -EINVAL; char *endptr; @@ -251,7 +251,7 @@ fail: int64_t qemu_strtosz_suffix(const char *nptr, char **end, const char default_suffix) { - return qemu_strtosz_suffix_unit(nptr, end, default_suffix, 1024); + return do_strtosz(nptr, end, default_suffix, 1024); } int64_t qemu_strtosz(const char *nptr, char **end) @@ -259,6 +259,11 @@ int64_t qemu_strtosz(const char *nptr, char **end) return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB); } +int64_t qemu_strtosz_metric(const char *nptr, char **end) +{ + return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_B, 1000); +} + /** * Helper function for error checking after strtol() and the like */ From e591591b323772eea733de6027f5e8b50692d0ff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:13:59 +0100 Subject: [PATCH 15/24] util/cutils: Rename qemu_strtosz() to qemu_strtosz_MiB() With qemu_strtosz(), no suffix means mebibytes. It's used rarely. I'm going to add a similar function where no suffix means bytes. Rename qemu_strtosz() to qemu_strtosz_MiB() to make the name qemu_strtosz() available for the new function. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-16-git-send-email-armbru@redhat.com> --- hmp.c | 2 +- hw/misc/ivshmem.c | 2 +- include/qemu/cutils.h | 2 +- monitor.c | 2 +- tests/test-cutils.c | 38 +++++++++++++++++++------------------- util/cutils.c | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/hmp.c b/hmp.c index aba728f0de..72a5256676 100644 --- a/hmp.c +++ b/hmp.c @@ -1385,7 +1385,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_MAX_BANDWIDTH: p.has_max_bandwidth = true; - valuebw = qemu_strtosz(valuestr, &endp); + valuebw = qemu_strtosz_MiB(valuestr, &endp); if (valuebw < 0 || (size_t)valuebw != valuebw || *endp != '\0') { error_setg(&err, "Invalid size %s", valuestr); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index bf57e635d6..b3d9ed99dd 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1268,7 +1268,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp) s->legacy_size = 4 << 20; /* 4 MB default */ } else { char *end; - int64_t size = qemu_strtosz(s->sizearg, &end); + int64_t size = qemu_strtosz_MiB(s->sizearg, &end); if (size < 0 || (size_t)size != size || *end != '\0' || !is_power_of_2(size)) { error_setg(errp, "Invalid size %s", s->sizearg); diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 81613d01ee..a08b1b03af 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -153,9 +153,9 @@ int parse_uint_full(const char *s, unsigned long long *value, int base); #define QEMU_STRTOSZ_DEFSUFFIX_MB 'M' #define QEMU_STRTOSZ_DEFSUFFIX_KB 'K' #define QEMU_STRTOSZ_DEFSUFFIX_B 'B' -int64_t qemu_strtosz(const char *nptr, char **end); int64_t qemu_strtosz_suffix(const char *nptr, char **end, const char default_suffix); +int64_t qemu_strtosz_MiB(const char *nptr, char **end); int64_t qemu_strtosz_metric(const char *nptr, char **end); #define K_BYTE (1ULL << 10) diff --git a/monitor.c b/monitor.c index 5953fc984f..c2c1e424f2 100644 --- a/monitor.c +++ b/monitor.c @@ -2811,7 +2811,7 @@ static QDict *monitor_parse_arguments(Monitor *mon, break; } } - val = qemu_strtosz(p, &end); + val = qemu_strtosz_MiB(p, &end); if (val < 0) { monitor_printf(mon, "invalid size\n"); goto fail; diff --git a/tests/test-cutils.c b/tests/test-cutils.c index e1d40548c0..9bbfb8f8e2 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1376,16 +1376,16 @@ static void test_qemu_strtosz_simple(void) int64_t res; str = "0"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, 0); g_assert(endptr == str + 1); str = "12345M"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, 12345 * M_BYTE); g_assert(endptr == str + 6); - res = qemu_strtosz(str, NULL); + res = qemu_strtosz_MiB(str, NULL); g_assert_cmpint(res, ==, 12345 * M_BYTE); /* Note: precision is 53 bits since we're parsing with strtod() */ @@ -1433,35 +1433,35 @@ static void test_qemu_strtosz_units(void) int64_t res; /* default is M */ - res = qemu_strtosz(none, &endptr); + res = qemu_strtosz_MiB(none, &endptr); g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == none + 1); - res = qemu_strtosz(b, &endptr); + res = qemu_strtosz_MiB(b, &endptr); g_assert_cmpint(res, ==, 1); g_assert(endptr == b + 2); - res = qemu_strtosz(k, &endptr); + res = qemu_strtosz_MiB(k, &endptr); g_assert_cmpint(res, ==, K_BYTE); g_assert(endptr == k + 2); - res = qemu_strtosz(m, &endptr); + res = qemu_strtosz_MiB(m, &endptr); g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == m + 2); - res = qemu_strtosz(g, &endptr); + res = qemu_strtosz_MiB(g, &endptr); g_assert_cmpint(res, ==, G_BYTE); g_assert(endptr == g + 2); - res = qemu_strtosz(t, &endptr); + res = qemu_strtosz_MiB(t, &endptr); g_assert_cmpint(res, ==, T_BYTE); g_assert(endptr == t + 2); - res = qemu_strtosz(p, &endptr); + res = qemu_strtosz_MiB(p, &endptr); g_assert_cmpint(res, ==, P_BYTE); g_assert(endptr == p + 2); - res = qemu_strtosz(e, &endptr); + res = qemu_strtosz_MiB(e, &endptr); g_assert_cmpint(res, ==, E_BYTE); g_assert(endptr == e + 2); } @@ -1472,7 +1472,7 @@ static void test_qemu_strtosz_float(void) char *endptr = NULL; int64_t res; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, 12.345 * M_BYTE); g_assert(endptr == str + 7); } @@ -1484,17 +1484,17 @@ static void test_qemu_strtosz_invalid(void) int64_t res; str = ""; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); str = " \t "; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); str = "crap"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); } @@ -1506,12 +1506,12 @@ static void test_qemu_strtosz_trailing(void) int64_t res; str = "123xxx"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, 123 * M_BYTE); g_assert(endptr == str + 3); str = "1kiB"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, 1024); g_assert(endptr == str + 2); } @@ -1523,7 +1523,7 @@ static void test_qemu_strtosz_erange(void) int64_t res; str = "-1"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 2); @@ -1543,7 +1543,7 @@ static void test_qemu_strtosz_erange(void) g_assert(endptr == str + 19); str = "10E"; - res = qemu_strtosz(str, &endptr); + res = qemu_strtosz_MiB(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 3); } diff --git a/util/cutils.c b/util/cutils.c index b46e254f83..9693adde14 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -254,7 +254,7 @@ int64_t qemu_strtosz_suffix(const char *nptr, char **end, return do_strtosz(nptr, end, default_suffix, 1024); } -int64_t qemu_strtosz(const char *nptr, char **end) +int64_t qemu_strtosz_MiB(const char *nptr, char **end) { return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB); } From 466dea14e677555dd24465aca75d00a3537ad062 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:00 +0100 Subject: [PATCH 16/24] util/cutils: New qemu_strtosz() Most callers of qemu_strtosz_suffix() pass QEMU_STRTOSZ_DEFSUFFIX_B. Capture the pattern in new qemu_strtosz(). Inline qemu_strtosz_suffix() into its only remaining caller. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-17-git-send-email-armbru@redhat.com> --- include/qemu/cutils.h | 17 +---------------- qapi/opts-visitor.c | 3 +-- qemu-img.c | 18 ++++++++---------- qemu-io-cmds.c | 2 +- tests/test-cutils.c | 16 ++++++++-------- util/cutils.c | 15 +++++++++++---- 6 files changed, 30 insertions(+), 41 deletions(-) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index a08b1b03af..3fdbb6b4c1 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -139,22 +139,7 @@ int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); int parse_uint_full(const char *s, unsigned long long *value, int base); -/* - * qemu_strtosz() suffixes used to specify the default treatment of an - * argument passed to qemu_strtosz() without an explicit suffix. - * These should be defined using upper case characters in the range - * A-Z, as qemu_strtosz() will use qemu_toupper() on the given argument - * prior to comparison. - */ -#define QEMU_STRTOSZ_DEFSUFFIX_EB 'E' -#define QEMU_STRTOSZ_DEFSUFFIX_PB 'P' -#define QEMU_STRTOSZ_DEFSUFFIX_TB 'T' -#define QEMU_STRTOSZ_DEFSUFFIX_GB 'G' -#define QEMU_STRTOSZ_DEFSUFFIX_MB 'M' -#define QEMU_STRTOSZ_DEFSUFFIX_KB 'K' -#define QEMU_STRTOSZ_DEFSUFFIX_B 'B' -int64_t qemu_strtosz_suffix(const char *nptr, char **end, - const char default_suffix); +int64_t qemu_strtosz(const char *nptr, char **end); int64_t qemu_strtosz_MiB(const char *nptr, char **end); int64_t qemu_strtosz_metric(const char *nptr, char **end); diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 1048bbc84e..360d33773f 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -489,8 +489,7 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) return; } - val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr, - QEMU_STRTOSZ_DEFSUFFIX_B); + val = qemu_strtosz(opt->str ? opt->str : "", &endptr); if (val < 0 || *endptr) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "a size value representible as a non-negative int64"); diff --git a/qemu-img.c b/qemu-img.c index cff22e3005..f1c641c0a1 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -462,8 +462,7 @@ static int img_create(int argc, char **argv) if (optind < argc) { int64_t sval; char *end; - sval = qemu_strtosz_suffix(argv[optind++], &end, - QEMU_STRTOSZ_DEFSUFFIX_B); + sval = qemu_strtosz(argv[optind++], &end); if (sval < 0 || *end) { if (sval == -ERANGE) { error_report("Image size must be less than 8 EiB!"); @@ -1865,7 +1864,7 @@ static int img_convert(int argc, char **argv) { int64_t sval; char *end; - sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + sval = qemu_strtosz(optarg, &end); if (sval < 0 || *end) { error_report("Invalid minimum zero buffer size for sparse output specified"); ret = -1; @@ -3653,8 +3652,7 @@ static int img_bench(int argc, char **argv) { char *end; errno = 0; - offset = qemu_strtosz_suffix(optarg, &end, - QEMU_STRTOSZ_DEFSUFFIX_B); + offset = qemu_strtosz(optarg, &end); if (offset < 0|| *end) { error_report("Invalid offset specified"); return 1; @@ -3670,7 +3668,7 @@ static int img_bench(int argc, char **argv) int64_t sval; char *end; - sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + sval = qemu_strtosz(optarg, &end); if (sval < 0 || sval > INT_MAX || *end) { error_report("Invalid buffer size specified"); return 1; @@ -3684,7 +3682,7 @@ static int img_bench(int argc, char **argv) int64_t sval; char *end; - sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + sval = qemu_strtosz(optarg, &end); if (sval < 0 || sval > INT_MAX || *end) { error_report("Invalid step size specified"); return 1; @@ -3847,7 +3845,7 @@ static int img_dd_bs(const char *arg, char *end; int64_t res; - res = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(arg, &end); if (res <= 0 || res > INT_MAX || *end) { error_report("invalid number: '%s'", arg); @@ -3864,7 +3862,7 @@ static int img_dd_count(const char *arg, { char *end; - dd->count = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + dd->count = qemu_strtosz(arg, &end); if (dd->count < 0 || *end) { error_report("invalid number: '%s'", arg); @@ -3898,7 +3896,7 @@ static int img_dd_skip(const char *arg, { char *end; - in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + in->offset = qemu_strtosz(arg, &end); if (in->offset < 0 || *end) { error_report("invalid number: '%s'", arg); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index e415b03cd0..0166cfaa8d 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -140,7 +140,7 @@ static int64_t cvtnum(const char *s) char *end; int64_t ret; - ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + ret = qemu_strtosz(s, &end); if (*end != '\0') { /* Detritus at the end of the string */ return -EINVAL; diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 9bbfb8f8e2..9eae06761f 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1391,27 +1391,27 @@ static void test_qemu_strtosz_simple(void) /* Note: precision is 53 bits since we're parsing with strtod() */ str = "9007199254740991"; /* 2^53-1 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0x1fffffffffffff); g_assert(endptr == str + 16); str = "9007199254740992"; /* 2^53 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0x20000000000000); g_assert(endptr == str + 16); str = "9007199254740993"; /* 2^53+1 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0x20000000000000); /* rounded to 53 bits */ g_assert(endptr == str + 16); str = "9223372036854774784"; /* 0x7ffffffffffffc00 (53 msbs set) */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0x7ffffffffffffc00); g_assert(endptr == str + 19); str = "9223372036854775295"; /* 0x7ffffffffffffdff */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0x7ffffffffffffc00); /* rounded to 53 bits */ g_assert(endptr == str + 19); @@ -1528,17 +1528,17 @@ static void test_qemu_strtosz_erange(void) g_assert(endptr == str + 2); str = "9223372036854775296"; /* 0x7ffffffffffffe00 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 19); str = "9223372036854775807"; /* 2^63-1 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 19); str = "9223372036854775808"; /* 2^63 */ - res = qemu_strtosz_suffix(str, &endptr, QEMU_STRTOSZ_DEFSUFFIX_B); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 19); diff --git a/util/cutils.c b/util/cutils.c index 9693adde14..97ec130606 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -178,6 +178,14 @@ int fcntl_setfl(int fd, int flag) } #endif +#define QEMU_STRTOSZ_DEFSUFFIX_EB 'E' +#define QEMU_STRTOSZ_DEFSUFFIX_PB 'P' +#define QEMU_STRTOSZ_DEFSUFFIX_TB 'T' +#define QEMU_STRTOSZ_DEFSUFFIX_GB 'G' +#define QEMU_STRTOSZ_DEFSUFFIX_MB 'M' +#define QEMU_STRTOSZ_DEFSUFFIX_KB 'K' +#define QEMU_STRTOSZ_DEFSUFFIX_B 'B' + static int64_t suffix_mul(char suffix, int64_t unit) { switch (qemu_toupper(suffix)) { @@ -248,15 +256,14 @@ fail: return retval; } -int64_t qemu_strtosz_suffix(const char *nptr, char **end, - const char default_suffix) +int64_t qemu_strtosz(const char *nptr, char **end) { - return do_strtosz(nptr, end, default_suffix, 1024); + return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_B, 1024); } int64_t qemu_strtosz_MiB(const char *nptr, char **end) { - return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB); + return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB, 1024); } int64_t qemu_strtosz_metric(const char *nptr, char **end) From 17f942560e54f8ee72996bc3276c697503606d7b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:01 +0100 Subject: [PATCH 17/24] util/cutils: Drop QEMU_STRTOSZ_DEFSUFFIX_* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing QEMU_STRTOSZ_DEFSUFFIX_* instead of '*' gains nothing. Get rid of these eyesores. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Message-Id: <1487708048-2131-18-git-send-email-armbru@redhat.com> --- util/cutils.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/util/cutils.c b/util/cutils.c index 97ec130606..0ac8019ef6 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -178,30 +178,22 @@ int fcntl_setfl(int fd, int flag) } #endif -#define QEMU_STRTOSZ_DEFSUFFIX_EB 'E' -#define QEMU_STRTOSZ_DEFSUFFIX_PB 'P' -#define QEMU_STRTOSZ_DEFSUFFIX_TB 'T' -#define QEMU_STRTOSZ_DEFSUFFIX_GB 'G' -#define QEMU_STRTOSZ_DEFSUFFIX_MB 'M' -#define QEMU_STRTOSZ_DEFSUFFIX_KB 'K' -#define QEMU_STRTOSZ_DEFSUFFIX_B 'B' - static int64_t suffix_mul(char suffix, int64_t unit) { switch (qemu_toupper(suffix)) { - case QEMU_STRTOSZ_DEFSUFFIX_B: + case 'B': return 1; - case QEMU_STRTOSZ_DEFSUFFIX_KB: + case 'K': return unit; - case QEMU_STRTOSZ_DEFSUFFIX_MB: + case 'M': return unit * unit; - case QEMU_STRTOSZ_DEFSUFFIX_GB: + case 'G': return unit * unit * unit; - case QEMU_STRTOSZ_DEFSUFFIX_TB: + case 'T': return unit * unit * unit * unit; - case QEMU_STRTOSZ_DEFSUFFIX_PB: + case 'P': return unit * unit * unit * unit * unit; - case QEMU_STRTOSZ_DEFSUFFIX_EB: + case 'E': return unit * unit * unit * unit * unit * unit; } return -1; @@ -258,17 +250,17 @@ fail: int64_t qemu_strtosz(const char *nptr, char **end) { - return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_B, 1024); + return do_strtosz(nptr, end, 'B', 1024); } int64_t qemu_strtosz_MiB(const char *nptr, char **end) { - return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB, 1024); + return do_strtosz(nptr, end, 'M', 1024); } int64_t qemu_strtosz_metric(const char *nptr, char **end) { - return do_strtosz(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_B, 1000); + return do_strtosz(nptr, end, 'B', 1000); } /** From 753f8da0e082eac66d4c86168e14f1c55c09aa44 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:02 +0100 Subject: [PATCH 18/24] test-cutils: Use qemu_strtosz() more often Use qemu_strtosz() instead of qemu_strtosz_MiB() where it doesn't really make a difference. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-19-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 9eae06761f..d492d1e72e 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1376,16 +1376,16 @@ static void test_qemu_strtosz_simple(void) int64_t res; str = "0"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 0); g_assert(endptr == str + 1); str = "12345M"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 12345 * M_BYTE); g_assert(endptr == str + 6); - res = qemu_strtosz_MiB(str, NULL); + res = qemu_strtosz(str, NULL); g_assert_cmpint(res, ==, 12345 * M_BYTE); /* Note: precision is 53 bits since we're parsing with strtod() */ @@ -1437,31 +1437,31 @@ static void test_qemu_strtosz_units(void) g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == none + 1); - res = qemu_strtosz_MiB(b, &endptr); + res = qemu_strtosz(b, &endptr); g_assert_cmpint(res, ==, 1); g_assert(endptr == b + 2); - res = qemu_strtosz_MiB(k, &endptr); + res = qemu_strtosz(k, &endptr); g_assert_cmpint(res, ==, K_BYTE); g_assert(endptr == k + 2); - res = qemu_strtosz_MiB(m, &endptr); + res = qemu_strtosz(m, &endptr); g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == m + 2); - res = qemu_strtosz_MiB(g, &endptr); + res = qemu_strtosz(g, &endptr); g_assert_cmpint(res, ==, G_BYTE); g_assert(endptr == g + 2); - res = qemu_strtosz_MiB(t, &endptr); + res = qemu_strtosz(t, &endptr); g_assert_cmpint(res, ==, T_BYTE); g_assert(endptr == t + 2); - res = qemu_strtosz_MiB(p, &endptr); + res = qemu_strtosz(p, &endptr); g_assert_cmpint(res, ==, P_BYTE); g_assert(endptr == p + 2); - res = qemu_strtosz_MiB(e, &endptr); + res = qemu_strtosz(e, &endptr); g_assert_cmpint(res, ==, E_BYTE); g_assert(endptr == e + 2); } @@ -1472,7 +1472,7 @@ static void test_qemu_strtosz_float(void) char *endptr = NULL; int64_t res; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 12.345 * M_BYTE); g_assert(endptr == str + 7); } @@ -1484,17 +1484,17 @@ static void test_qemu_strtosz_invalid(void) int64_t res; str = ""; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); str = " \t "; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); str = "crap"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -EINVAL); g_assert(endptr == str); } @@ -1511,7 +1511,7 @@ static void test_qemu_strtosz_trailing(void) g_assert(endptr == str + 3); str = "1kiB"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 1024); g_assert(endptr == str + 2); } @@ -1523,7 +1523,7 @@ static void test_qemu_strtosz_erange(void) int64_t res; str = "-1"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 2); @@ -1543,7 +1543,7 @@ static void test_qemu_strtosz_erange(void) g_assert(endptr == str + 19); str = "10E"; - res = qemu_strtosz_MiB(str, &endptr); + res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, -ERANGE); g_assert(endptr == str + 3); } From dab9cc9237e3e1794053780e43787be8a07b22db Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:03 +0100 Subject: [PATCH 19/24] test-cutils: Drop suffix from test_qemu_strtosz_simple() Leave testing unit suffixes to test_qemu_strtosz_units(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-20-git-send-email-armbru@redhat.com> --- tests/test-cutils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index d492d1e72e..c4437d9817 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1380,13 +1380,13 @@ static void test_qemu_strtosz_simple(void) g_assert_cmpint(res, ==, 0); g_assert(endptr == str + 1); - str = "12345M"; + str = "12345"; res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, 12345 * M_BYTE); - g_assert(endptr == str + 6); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); res = qemu_strtosz(str, NULL); - g_assert_cmpint(res, ==, 12345 * M_BYTE); + g_assert_cmpint(res, ==, 12345); /* Note: precision is 53 bits since we're parsing with strtod() */ From 606caa0a2abdb8ff9174bb5bd5861ed2b63d1de2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:04 +0100 Subject: [PATCH 20/24] qemu-img: Wrap cvtnum() around qemu_strtosz() Cc: Kevin Wolf Cc: Max Reitz Cc: qemu-block@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-21-git-send-email-armbru@redhat.com> --- qemu-img.c | 58 +++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index f1c641c0a1..4062917603 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -368,6 +368,19 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, return 0; } +static int64_t cvtnum(const char *s) +{ + char *end; + int64_t ret; + + ret = qemu_strtosz(s, &end); + if (*end != '\0') { + /* Detritus at the end of the string */ + return -EINVAL; + } + return ret; +} + static int img_create(int argc, char **argv) { int c; @@ -461,9 +474,9 @@ static int img_create(int argc, char **argv) /* Get image size, if specified */ if (optind < argc) { int64_t sval; - char *end; - sval = qemu_strtosz(argv[optind++], &end); - if (sval < 0 || *end) { + + sval = cvtnum(argv[optind++]); + if (sval < 0) { if (sval == -ERANGE) { error_report("Image size must be less than 8 EiB!"); } else { @@ -1863,9 +1876,9 @@ static int img_convert(int argc, char **argv) case 'S': { int64_t sval; - char *end; - sval = qemu_strtosz(optarg, &end); - if (sval < 0 || *end) { + + sval = cvtnum(optarg); + if (sval < 0) { error_report("Invalid minimum zero buffer size for sparse output specified"); ret = -1; goto fail_getopt; @@ -3650,10 +3663,8 @@ static int img_bench(int argc, char **argv) break; case 'o': { - char *end; - errno = 0; - offset = qemu_strtosz(optarg, &end); - if (offset < 0|| *end) { + offset = cvtnum(optarg); + if (offset < 0) { error_report("Invalid offset specified"); return 1; } @@ -3666,10 +3677,9 @@ static int img_bench(int argc, char **argv) case 's': { int64_t sval; - char *end; - sval = qemu_strtosz(optarg, &end); - if (sval < 0 || sval > INT_MAX || *end) { + sval = cvtnum(optarg); + if (sval < 0 || sval > INT_MAX) { error_report("Invalid buffer size specified"); return 1; } @@ -3680,10 +3690,9 @@ static int img_bench(int argc, char **argv) case 'S': { int64_t sval; - char *end; - sval = qemu_strtosz(optarg, &end); - if (sval < 0 || sval > INT_MAX || *end) { + sval = cvtnum(optarg); + if (sval < 0 || sval > INT_MAX) { error_report("Invalid step size specified"); return 1; } @@ -3842,12 +3851,11 @@ static int img_dd_bs(const char *arg, struct DdIo *in, struct DdIo *out, struct DdInfo *dd) { - char *end; int64_t res; - res = qemu_strtosz(arg, &end); + res = cvtnum(arg); - if (res <= 0 || res > INT_MAX || *end) { + if (res <= 0 || res > INT_MAX) { error_report("invalid number: '%s'", arg); return 1; } @@ -3860,11 +3868,9 @@ static int img_dd_count(const char *arg, struct DdIo *in, struct DdIo *out, struct DdInfo *dd) { - char *end; + dd->count = cvtnum(arg); - dd->count = qemu_strtosz(arg, &end); - - if (dd->count < 0 || *end) { + if (dd->count < 0) { error_report("invalid number: '%s'", arg); return 1; } @@ -3894,11 +3900,9 @@ static int img_dd_skip(const char *arg, struct DdIo *in, struct DdIo *out, struct DdInfo *dd) { - char *end; + in->offset = cvtnum(arg); - in->offset = qemu_strtosz(arg, &end); - - if (in->offset < 0 || *end) { + if (in->offset < 0) { error_report("invalid number: '%s'", arg); return 1; } From 4fcdf65ae2c00ae69f7625f26ed41f37d77b403c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:05 +0100 Subject: [PATCH 21/24] util/cutils: Let qemu_strtosz*() optionally reject trailing crap Change the qemu_strtosz() & friends to return -EINVAL when @endptr is null and the conversion doesn't consume the string completely. Matches how qemu_strtol() & friends work. Only test_qemu_strtosz_simple() passes a null @endptr. No functional change there, because its conversion consumes the string. Simplify callers that use @endptr only to fail when it doesn't point to '\0' to pass a null @endptr instead. Cc: Dr. David Alan Gilbert Cc: Eduardo Habkost (maintainer:X86) Cc: Kevin Wolf (supporter:Block layer core) Cc: Max Reitz (supporter:Block layer core) Cc: qemu-block@nongnu.org (open list:Block layer core) Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Dr. David Alan Gilbert Message-Id: <1487708048-2131-22-git-send-email-armbru@redhat.com> --- hmp.c | 6 ++---- hw/misc/ivshmem.c | 6 ++---- qapi/opts-visitor.c | 5 ++--- qemu-img.c | 7 +------ qemu-io-cmds.c | 7 +------ target/i386/cpu.c | 5 ++--- tests/test-cutils.c | 6 ++++++ util/cutils.c | 14 +++++++++----- 8 files changed, 25 insertions(+), 31 deletions(-) diff --git a/hmp.c b/hmp.c index 72a5256676..2269e8b457 100644 --- a/hmp.c +++ b/hmp.c @@ -1346,7 +1346,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) const char *valuestr = qdict_get_str(qdict, "value"); int64_t valuebw = 0; long valueint = 0; - char *endp; Error *err = NULL; bool use_int_value = false; int i; @@ -1385,9 +1384,8 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_MAX_BANDWIDTH: p.has_max_bandwidth = true; - valuebw = qemu_strtosz_MiB(valuestr, &endp); - if (valuebw < 0 || (size_t)valuebw != valuebw - || *endp != '\0') { + valuebw = qemu_strtosz_MiB(valuestr, NULL); + if (valuebw < 0 || (size_t)valuebw != valuebw) { error_setg(&err, "Invalid size %s", valuestr); goto cleanup; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index b3d9ed99dd..848bebc794 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1267,10 +1267,8 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp) if (s->sizearg == NULL) { s->legacy_size = 4 << 20; /* 4 MB default */ } else { - char *end; - int64_t size = qemu_strtosz_MiB(s->sizearg, &end); - if (size < 0 || (size_t)size != size || *end != '\0' - || !is_power_of_2(size)) { + int64_t size = qemu_strtosz_MiB(s->sizearg, NULL); + if (size < 0 || (size_t)size != size || !is_power_of_2(size)) { error_setg(errp, "Invalid size %s", s->sizearg); return; } diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 360d33773f..911a0ee300 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -482,15 +482,14 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) OptsVisitor *ov = to_ov(v); const QemuOpt *opt; int64_t val; - char *endptr; opt = lookup_scalar(ov, name, errp); if (!opt) { return; } - val = qemu_strtosz(opt->str ? opt->str : "", &endptr); - if (val < 0 || *endptr) { + val = qemu_strtosz(opt->str ? opt->str : "", NULL); + if (val < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "a size value representible as a non-negative int64"); return; diff --git a/qemu-img.c b/qemu-img.c index 4062917603..39ef581cc1 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -370,14 +370,9 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, static int64_t cvtnum(const char *s) { - char *end; int64_t ret; - ret = qemu_strtosz(s, &end); - if (*end != '\0') { - /* Detritus at the end of the string */ - return -EINVAL; - } + ret = qemu_strtosz(s, NULL); return ret; } diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 0166cfaa8d..973eb94774 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -137,14 +137,9 @@ static char **breakline(char *input, int *count) static int64_t cvtnum(const char *s) { - char *end; int64_t ret; - ret = qemu_strtosz(s, &end); - if (*end != '\0') { - /* Detritus at the end of the string */ - return -EINVAL; - } + ret = qemu_strtosz(s, NULL); return ret; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 685ca36640..58a05ec870 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2034,10 +2034,9 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, /* Special case: */ if (!strcmp(name, "tsc-freq")) { int64_t tsc_freq; - char *err; - tsc_freq = qemu_strtosz_metric(val, &err); - if (tsc_freq < 0 || *err) { + tsc_freq = qemu_strtosz_metric(val, NULL); + if (tsc_freq < 0) { error_setg(errp, "bad numerical value %s", val); return; } diff --git a/tests/test-cutils.c b/tests/test-cutils.c index c4437d9817..f2ecb7aecb 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1510,10 +1510,16 @@ static void test_qemu_strtosz_trailing(void) g_assert_cmpint(res, ==, 123 * M_BYTE); g_assert(endptr == str + 3); + res = qemu_strtosz(str, NULL); + g_assert_cmpint(res, ==, -EINVAL); + str = "1kiB"; res = qemu_strtosz(str, &endptr); g_assert_cmpint(res, ==, 1024); g_assert(endptr == str + 2); + + res = qemu_strtosz(str, NULL); + g_assert_cmpint(res, ==, -EINVAL); } static void test_qemu_strtosz_erange(void) diff --git a/util/cutils.c b/util/cutils.c index 0ac8019ef6..b991623733 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -208,7 +208,7 @@ static int64_t suffix_mul(char suffix, int64_t unit) static int64_t do_strtosz(const char *nptr, char **end, const char default_suffix, int64_t unit) { - int64_t retval = -EINVAL; + int64_t retval; char *endptr; unsigned char c; int mul_required = 0; @@ -217,7 +217,8 @@ static int64_t do_strtosz(const char *nptr, char **end, errno = 0; val = strtod(nptr, &endptr); if (isnan(val) || endptr == nptr || errno != 0) { - goto fail; + retval = -EINVAL; + goto out; } fraction = modf(val, &integral); if (fraction != 0) { @@ -232,17 +233,20 @@ static int64_t do_strtosz(const char *nptr, char **end, assert(mul >= 0); } if (mul == 1 && mul_required) { - goto fail; + retval = -EINVAL; + goto out; } if ((val * mul >= INT64_MAX) || val < 0) { retval = -ERANGE; - goto fail; + goto out; } retval = val * mul; -fail: +out: if (end) { *end = endptr; + } else if (*endptr) { + retval = -EINVAL; } return retval; From f17fd4fdf0df3d2f3444399d04c38d22b9a3e1b7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:06 +0100 Subject: [PATCH 22/24] util/cutils: Return qemu_strtosz*() error and value separately This makes qemu_strtosz(), qemu_strtosz_mebi() and qemu_strtosz_metric() similar to qemu_strtoi64(), except negative values are rejected. Cc: Dr. David Alan Gilbert Cc: Eduardo Habkost (maintainer:X86) Cc: Kevin Wolf (supporter:Block layer core) Cc: Max Reitz (supporter:Block layer core) Cc: qemu-block@nongnu.org (open list:Block layer core) Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Dr. David Alan Gilbert Message-Id: <1487708048-2131-23-git-send-email-armbru@redhat.com> --- hmp.c | 6 +-- hw/misc/ivshmem.c | 7 ++- include/qemu/cutils.h | 6 +-- monitor.c | 5 +- qapi/opts-visitor.c | 5 +- qemu-img.c | 10 ++-- qemu-io-cmds.c | 10 ++-- target/i386/cpu.c | 5 +- tests/test-cutils.c | 120 +++++++++++++++++++++++++----------------- util/cutils.c | 22 ++++---- 10 files changed, 119 insertions(+), 77 deletions(-) diff --git a/hmp.c b/hmp.c index 2269e8b457..d16761f32e 100644 --- a/hmp.c +++ b/hmp.c @@ -1348,7 +1348,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) long valueint = 0; Error *err = NULL; bool use_int_value = false; - int i; + int i, ret; for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { if (strcmp(param, MigrationParameter_lookup[i]) == 0) { @@ -1384,8 +1384,8 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_MAX_BANDWIDTH: p.has_max_bandwidth = true; - valuebw = qemu_strtosz_MiB(valuestr, NULL); - if (valuebw < 0 || (size_t)valuebw != valuebw) { + ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw); + if (ret < 0 || (size_t)valuebw != valuebw) { error_setg(&err, "Invalid size %s", valuestr); goto cleanup; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 848bebc794..80856fd6a9 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1267,8 +1267,11 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp) if (s->sizearg == NULL) { s->legacy_size = 4 << 20; /* 4 MB default */ } else { - int64_t size = qemu_strtosz_MiB(s->sizearg, NULL); - if (size < 0 || (size_t)size != size || !is_power_of_2(size)) { + int ret; + int64_t size; + + ret = qemu_strtosz_MiB(s->sizearg, NULL, &size); + if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) { error_setg(errp, "Invalid size %s", s->sizearg); return; } diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 3fdbb6b4c1..4c68d5c7c1 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -139,9 +139,9 @@ int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); int parse_uint_full(const char *s, unsigned long long *value, int base); -int64_t qemu_strtosz(const char *nptr, char **end); -int64_t qemu_strtosz_MiB(const char *nptr, char **end); -int64_t qemu_strtosz_metric(const char *nptr, char **end); +int qemu_strtosz(const char *nptr, char **end, int64_t *result); +int qemu_strtosz_MiB(const char *nptr, char **end, int64_t *result); +int qemu_strtosz_metric(const char *nptr, char **end, int64_t *result); #define K_BYTE (1ULL << 10) #define M_BYTE (1ULL << 20) diff --git a/monitor.c b/monitor.c index c2c1e424f2..8baeaf0ff3 100644 --- a/monitor.c +++ b/monitor.c @@ -2799,6 +2799,7 @@ static QDict *monitor_parse_arguments(Monitor *mon, break; case 'o': { + int ret; int64_t val; char *end; @@ -2811,8 +2812,8 @@ static QDict *monitor_parse_arguments(Monitor *mon, break; } } - val = qemu_strtosz_MiB(p, &end); - if (val < 0) { + ret = qemu_strtosz_MiB(p, &end, &val); + if (ret < 0) { monitor_printf(mon, "invalid size\n"); goto fail; } diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 911a0ee300..aac2e09e1f 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -482,14 +482,15 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) OptsVisitor *ov = to_ov(v); const QemuOpt *opt; int64_t val; + int err; opt = lookup_scalar(ov, name, errp); if (!opt) { return; } - val = qemu_strtosz(opt->str ? opt->str : "", NULL); - if (val < 0) { + err = qemu_strtosz(opt->str ? opt->str : "", NULL, &val); + if (err < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "a size value representible as a non-negative int64"); return; diff --git a/qemu-img.c b/qemu-img.c index 39ef581cc1..37d1afb839 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -370,10 +370,14 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, static int64_t cvtnum(const char *s) { - int64_t ret; + int err; + int64_t value; - ret = qemu_strtosz(s, NULL); - return ret; + err = qemu_strtosz(s, NULL, &value); + if (err < 0) { + return err; + } + return value; } static int img_create(int argc, char **argv) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 973eb94774..01a6dc6fbc 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -137,10 +137,14 @@ static char **breakline(char *input, int *count) static int64_t cvtnum(const char *s) { - int64_t ret; + int err; + int64_t value; - ret = qemu_strtosz(s, NULL); - return ret; + err = qemu_strtosz(s, NULL, &value); + if (err < 0) { + return err; + } + return value; } static void print_cvtnum_err(int64_t rc, const char *arg) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 58a05ec870..d32af9700a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2033,10 +2033,11 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, /* Special case: */ if (!strcmp(name, "tsc-freq")) { + int ret; int64_t tsc_freq; - tsc_freq = qemu_strtosz_metric(val, NULL); - if (tsc_freq < 0) { + ret = qemu_strtosz_metric(val, NULL, &tsc_freq); + if (ret < 0) { error_setg(errp, "bad numerical value %s", val); return; } diff --git a/tests/test-cutils.c b/tests/test-cutils.c index f2ecb7aecb..d0137debd0 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1373,45 +1373,54 @@ static void test_qemu_strtosz_simple(void) { const char *str; char *endptr = NULL; - int64_t res; + int err; + int64_t res = 0xbaadf00d; str = "0"; - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0); g_assert(endptr == str + 1); str = "12345"; - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); g_assert(endptr == str + 5); - res = qemu_strtosz(str, NULL); + err = qemu_strtosz(str, NULL, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345); /* Note: precision is 53 bits since we're parsing with strtod() */ str = "9007199254740991"; /* 2^53-1 */ - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x1fffffffffffff); g_assert(endptr == str + 16); str = "9007199254740992"; /* 2^53 */ - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x20000000000000); g_assert(endptr == str + 16); str = "9007199254740993"; /* 2^53+1 */ - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x20000000000000); /* rounded to 53 bits */ g_assert(endptr == str + 16); str = "9223372036854774784"; /* 0x7ffffffffffffc00 (53 msbs set) */ - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x7ffffffffffffc00); g_assert(endptr == str + 19); str = "9223372036854775295"; /* 0x7ffffffffffffdff */ - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 0x7ffffffffffffc00); /* rounded to 53 bits */ g_assert(endptr == str + 19); @@ -1429,39 +1438,48 @@ static void test_qemu_strtosz_units(void) const char *t = "1T"; const char *p = "1P"; const char *e = "1E"; + int err; char *endptr = NULL; - int64_t res; + int64_t res = 0xbaadf00d; /* default is M */ - res = qemu_strtosz_MiB(none, &endptr); + err = qemu_strtosz_MiB(none, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == none + 1); - res = qemu_strtosz(b, &endptr); + err = qemu_strtosz(b, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1); g_assert(endptr == b + 2); - res = qemu_strtosz(k, &endptr); + err = qemu_strtosz(k, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, K_BYTE); g_assert(endptr == k + 2); - res = qemu_strtosz(m, &endptr); + err = qemu_strtosz(m, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, M_BYTE); g_assert(endptr == m + 2); - res = qemu_strtosz(g, &endptr); + err = qemu_strtosz(g, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, G_BYTE); g_assert(endptr == g + 2); - res = qemu_strtosz(t, &endptr); + err = qemu_strtosz(t, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, T_BYTE); g_assert(endptr == t + 2); - res = qemu_strtosz(p, &endptr); + err = qemu_strtosz(p, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, P_BYTE); g_assert(endptr == p + 2); - res = qemu_strtosz(e, &endptr); + err = qemu_strtosz(e, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, E_BYTE); g_assert(endptr == e + 2); } @@ -1469,10 +1487,12 @@ static void test_qemu_strtosz_units(void) static void test_qemu_strtosz_float(void) { const char *str = "12.345M"; + int err; char *endptr = NULL; - int64_t res; + int64_t res = 0xbaadf00d; - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12.345 * M_BYTE); g_assert(endptr == str + 7); } @@ -1481,21 +1501,22 @@ static void test_qemu_strtosz_invalid(void) { const char *str; char *endptr = NULL; - int64_t res; + int err; + int64_t res = 0xbaadf00d; str = ""; - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -EINVAL); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); str = " \t "; - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -EINVAL); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); str = "crap"; - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -EINVAL); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -EINVAL); g_assert(endptr == str); } @@ -1503,64 +1524,69 @@ static void test_qemu_strtosz_trailing(void) { const char *str; char *endptr = NULL; - int64_t res; + int err; + int64_t res = 0xbaadf00d; str = "123xxx"; - res = qemu_strtosz_MiB(str, &endptr); + err = qemu_strtosz_MiB(str, &endptr, &res); g_assert_cmpint(res, ==, 123 * M_BYTE); g_assert(endptr == str + 3); - res = qemu_strtosz(str, NULL); - g_assert_cmpint(res, ==, -EINVAL); + err = qemu_strtosz(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); str = "1kiB"; - res = qemu_strtosz(str, &endptr); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 1024); g_assert(endptr == str + 2); - res = qemu_strtosz(str, NULL); - g_assert_cmpint(res, ==, -EINVAL); + err = qemu_strtosz(str, NULL, &res); + g_assert_cmpint(err, ==, -EINVAL); } static void test_qemu_strtosz_erange(void) { const char *str; char *endptr = NULL; - int64_t res; + int err; + int64_t res = 0xbaadf00d; str = "-1"; - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -ERANGE); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 2); str = "9223372036854775296"; /* 0x7ffffffffffffe00 */ - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -ERANGE); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 19); str = "9223372036854775807"; /* 2^63-1 */ - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -ERANGE); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 19); str = "9223372036854775808"; /* 2^63 */ - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -ERANGE); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 19); str = "10E"; - res = qemu_strtosz(str, &endptr); - g_assert_cmpint(res, ==, -ERANGE); + err = qemu_strtosz(str, &endptr, &res); + g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 3); } static void test_qemu_strtosz_metric(void) { const char *str = "12345k"; + int err; char *endptr = NULL; - int64_t res; + int64_t res = 0xbaadf00d; - res = qemu_strtosz_metric(str, &endptr); + err = qemu_strtosz_metric(str, &endptr, &res); + g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, 12345000); g_assert(endptr == str + 6); } diff --git a/util/cutils.c b/util/cutils.c index b991623733..7088ddcb09 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -205,10 +205,11 @@ static int64_t suffix_mul(char suffix, int64_t unit) * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on * other error. */ -static int64_t do_strtosz(const char *nptr, char **end, - const char default_suffix, int64_t unit) +static int do_strtosz(const char *nptr, char **end, + const char default_suffix, int64_t unit, + int64_t *result) { - int64_t retval; + int retval; char *endptr; unsigned char c; int mul_required = 0; @@ -240,7 +241,8 @@ static int64_t do_strtosz(const char *nptr, char **end, retval = -ERANGE; goto out; } - retval = val * mul; + *result = val * mul; + retval = 0; out: if (end) { @@ -252,19 +254,19 @@ out: return retval; } -int64_t qemu_strtosz(const char *nptr, char **end) +int qemu_strtosz(const char *nptr, char **end, int64_t *result) { - return do_strtosz(nptr, end, 'B', 1024); + return do_strtosz(nptr, end, 'B', 1024, result); } -int64_t qemu_strtosz_MiB(const char *nptr, char **end) +int qemu_strtosz_MiB(const char *nptr, char **end, int64_t *result) { - return do_strtosz(nptr, end, 'M', 1024); + return do_strtosz(nptr, end, 'M', 1024, result); } -int64_t qemu_strtosz_metric(const char *nptr, char **end) +int qemu_strtosz_metric(const char *nptr, char **end, int64_t *result) { - return do_strtosz(nptr, end, 'B', 1000); + return do_strtosz(nptr, end, 'B', 1000, result); } /** From f46bfdbfc8f95cf65d7818ef68a801e063c40332 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:07 +0100 Subject: [PATCH 23/24] util/cutils: Change qemu_strtosz*() from int64_t to uint64_t This will permit its use in parse_option_size(). Cc: Dr. David Alan Gilbert Cc: Eduardo Habkost (maintainer:X86) Cc: Kevin Wolf (supporter:Block layer core) Cc: Max Reitz (supporter:Block layer core) Cc: qemu-block@nongnu.org (open list:Block layer core) Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Dr. David Alan Gilbert Message-Id: <1487708048-2131-24-git-send-email-armbru@redhat.com> --- hmp.c | 5 +++-- hw/misc/ivshmem.c | 2 +- include/qemu/cutils.h | 6 +++--- monitor.c | 4 ++-- qapi/opts-visitor.c | 6 ++---- qemu-img.c | 5 ++++- qemu-io-cmds.c | 5 ++++- target/i386/cpu.c | 4 ++-- tests/test-cutils.c | 40 ++++++++++++++++++++-------------------- util/cutils.c | 14 +++++++++----- 10 files changed, 50 insertions(+), 41 deletions(-) diff --git a/hmp.c b/hmp.c index d16761f32e..83e287e0a4 100644 --- a/hmp.c +++ b/hmp.c @@ -1344,7 +1344,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) { const char *param = qdict_get_str(qdict, "parameter"); const char *valuestr = qdict_get_str(qdict, "value"); - int64_t valuebw = 0; + uint64_t valuebw = 0; long valueint = 0; Error *err = NULL; bool use_int_value = false; @@ -1385,7 +1385,8 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) case MIGRATION_PARAMETER_MAX_BANDWIDTH: p.has_max_bandwidth = true; ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw); - if (ret < 0 || (size_t)valuebw != valuebw) { + if (ret < 0 || valuebw > INT64_MAX + || (size_t)valuebw != valuebw) { error_setg(&err, "Invalid size %s", valuestr); goto cleanup; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 80856fd6a9..82ce8378bf 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -1268,7 +1268,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp) s->legacy_size = 4 << 20; /* 4 MB default */ } else { int ret; - int64_t size; + uint64_t size; ret = qemu_strtosz_MiB(s->sizearg, NULL, &size); if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) { diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 4c68d5c7c1..f0878eaafa 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -139,9 +139,9 @@ int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); int parse_uint_full(const char *s, unsigned long long *value, int base); -int qemu_strtosz(const char *nptr, char **end, int64_t *result); -int qemu_strtosz_MiB(const char *nptr, char **end, int64_t *result); -int qemu_strtosz_metric(const char *nptr, char **end, int64_t *result); +int qemu_strtosz(const char *nptr, char **end, uint64_t *result); +int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result); +int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result); #define K_BYTE (1ULL << 10) #define M_BYTE (1ULL << 20) diff --git a/monitor.c b/monitor.c index 8baeaf0ff3..4ac2702276 100644 --- a/monitor.c +++ b/monitor.c @@ -2800,7 +2800,7 @@ static QDict *monitor_parse_arguments(Monitor *mon, case 'o': { int ret; - int64_t val; + uint64_t val; char *end; while (qemu_isspace(*p)) { @@ -2813,7 +2813,7 @@ static QDict *monitor_parse_arguments(Monitor *mon, } } ret = qemu_strtosz_MiB(p, &end, &val); - if (ret < 0) { + if (ret < 0 || val > INT64_MAX) { monitor_printf(mon, "invalid size\n"); goto fail; } diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index aac2e09e1f..a0a7c0e734 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -481,7 +481,6 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); const QemuOpt *opt; - int64_t val; int err; opt = lookup_scalar(ov, name, errp); @@ -489,14 +488,13 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) return; } - err = qemu_strtosz(opt->str ? opt->str : "", NULL, &val); + err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj); if (err < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "a size value representible as a non-negative int64"); + "a size value"); return; } - *obj = val; processed(ov, name); } diff --git a/qemu-img.c b/qemu-img.c index 37d1afb839..df3aefd35a 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -371,12 +371,15 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts, static int64_t cvtnum(const char *s) { int err; - int64_t value; + uint64_t value; err = qemu_strtosz(s, NULL, &value); if (err < 0) { return err; } + if (value > INT64_MAX) { + return -ERANGE; + } return value; } diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 01a6dc6fbc..7ac1576d4c 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -138,12 +138,15 @@ static char **breakline(char *input, int *count) static int64_t cvtnum(const char *s) { int err; - int64_t value; + uint64_t value; err = qemu_strtosz(s, NULL, &value); if (err < 0) { return err; } + if (value > INT64_MAX) { + return -ERANGE; + } return value; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d32af9700a..b6f157dca3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2034,10 +2034,10 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, /* Special case: */ if (!strcmp(name, "tsc-freq")) { int ret; - int64_t tsc_freq; + uint64_t tsc_freq; ret = qemu_strtosz_metric(val, NULL, &tsc_freq); - if (ret < 0) { + if (ret < 0 || tsc_freq > INT64_MAX) { error_setg(errp, "bad numerical value %s", val); return; } diff --git a/tests/test-cutils.c b/tests/test-cutils.c index d0137debd0..f64a49b7fb 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1374,7 +1374,7 @@ static void test_qemu_strtosz_simple(void) const char *str; char *endptr = NULL; int err; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; str = "0"; err = qemu_strtosz(str, &endptr, &res); @@ -1412,17 +1412,17 @@ static void test_qemu_strtosz_simple(void) g_assert_cmpint(res, ==, 0x20000000000000); /* rounded to 53 bits */ g_assert(endptr == str + 16); - str = "9223372036854774784"; /* 0x7ffffffffffffc00 (53 msbs set) */ + str = "18446744073709549568"; /* 0xfffffffffffff800 (53 msbs set) */ err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x7ffffffffffffc00); - g_assert(endptr == str + 19); + g_assert_cmpint(res, ==, 0xfffffffffffff800); + g_assert(endptr == str + 20); - str = "9223372036854775295"; /* 0x7ffffffffffffdff */ + str = "18446744073709550591"; /* 0xfffffffffffffbff */ err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); - g_assert_cmpint(res, ==, 0x7ffffffffffffc00); /* rounded to 53 bits */ - g_assert(endptr == str + 19); + g_assert_cmpint(res, ==, 0xfffffffffffff800); /* rounded to 53 bits */ + g_assert(endptr == str + 20); /* 0x7ffffffffffffe00..0x7fffffffffffffff get rounded to * 0x8000000000000000, thus -ERANGE; see test_qemu_strtosz_erange() */ @@ -1440,7 +1440,7 @@ static void test_qemu_strtosz_units(void) const char *e = "1E"; int err; char *endptr = NULL; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; /* default is M */ err = qemu_strtosz_MiB(none, &endptr, &res); @@ -1489,7 +1489,7 @@ static void test_qemu_strtosz_float(void) const char *str = "12.345M"; int err; char *endptr = NULL; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, 0); @@ -1502,7 +1502,7 @@ static void test_qemu_strtosz_invalid(void) const char *str; char *endptr = NULL; int err; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; str = ""; err = qemu_strtosz(str, &endptr, &res); @@ -1525,7 +1525,7 @@ static void test_qemu_strtosz_trailing(void) const char *str; char *endptr = NULL; int err; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; str = "123xxx"; err = qemu_strtosz_MiB(str, &endptr, &res); @@ -1550,29 +1550,29 @@ static void test_qemu_strtosz_erange(void) const char *str; char *endptr = NULL; int err; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; str = "-1"; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 2); - str = "9223372036854775296"; /* 0x7ffffffffffffe00 */ + str = "18446744073709550592"; /* 0xfffffffffffffc00 */ err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert(endptr == str + 19); + g_assert(endptr == str + 20); - str = "9223372036854775807"; /* 2^63-1 */ + str = "18446744073709551615"; /* 2^64-1 */ err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert(endptr == str + 19); + g_assert(endptr == str + 20); - str = "9223372036854775808"; /* 2^63 */ + str = "18446744073709551616"; /* 2^64 */ err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); - g_assert(endptr == str + 19); + g_assert(endptr == str + 20); - str = "10E"; + str = "20E"; err = qemu_strtosz(str, &endptr, &res); g_assert_cmpint(err, ==, -ERANGE); g_assert(endptr == str + 3); @@ -1583,7 +1583,7 @@ static void test_qemu_strtosz_metric(void) const char *str = "12345k"; int err; char *endptr = NULL; - int64_t res = 0xbaadf00d; + uint64_t res = 0xbaadf00d; err = qemu_strtosz_metric(str, &endptr, &res); g_assert_cmpint(err, ==, 0); diff --git a/util/cutils.c b/util/cutils.c index 7088ddcb09..50ad179dc5 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -207,7 +207,7 @@ static int64_t suffix_mul(char suffix, int64_t unit) */ static int do_strtosz(const char *nptr, char **end, const char default_suffix, int64_t unit, - int64_t *result) + uint64_t *result) { int retval; char *endptr; @@ -237,7 +237,11 @@ static int do_strtosz(const char *nptr, char **end, retval = -EINVAL; goto out; } - if ((val * mul >= INT64_MAX) || val < 0) { + /* + * Values >= 0xfffffffffffffc00 overflow uint64_t after their trip + * through double (53 bits of precision). + */ + if ((val * mul >= 0xfffffffffffffc00) || val < 0) { retval = -ERANGE; goto out; } @@ -254,17 +258,17 @@ out: return retval; } -int qemu_strtosz(const char *nptr, char **end, int64_t *result) +int qemu_strtosz(const char *nptr, char **end, uint64_t *result) { return do_strtosz(nptr, end, 'B', 1024, result); } -int qemu_strtosz_MiB(const char *nptr, char **end, int64_t *result) +int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result) { return do_strtosz(nptr, end, 'M', 1024, result); } -int qemu_strtosz_metric(const char *nptr, char **end, int64_t *result) +int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result) { return do_strtosz(nptr, end, 'B', 1000, result); } From 75cdcd1553e74b5edc58aed23e3b2da8dabb1876 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 21 Feb 2017 21:14:08 +0100 Subject: [PATCH 24/24] option: Fix checking of sizes for overflow and trailing crap parse_option_size()'s checking for overflow and trailing crap is wrong. Has always been that way. qemu_strtosz() gets it right, so use that. This adds support for size suffixes 'P', 'E', and ignores case for all suffixes, not just 'k'. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1487708048-2131-25-git-send-email-armbru@redhat.com> --- tests/test-qemu-opts.c | 21 +++++++++------------ util/qemu-option.c | 41 +++++++++++++---------------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index 8b92f7b0dc..c46ef31658 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -702,10 +702,9 @@ static void test_opts_parse_size(void) g_assert(!opts); opts = qemu_opts_parse(&opts_list_02, "size1=18446744073709550592", /* fffffffffffffc00 */ - false, &error_abort); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); + false, &err); + error_free_or_abort(&err); + g_assert(!opts); /* Suffixes */ opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M", @@ -723,19 +722,17 @@ static void test_opts_parse_size(void) /* Beyond limit with suffix */ opts = qemu_opts_parse(&opts_list_02, "size1=16777216T", - false, &error_abort); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0); + false, &err); + error_free_or_abort(&err); + g_assert(!opts); /* Trailing crap */ opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err); error_free_or_abort(&err); g_assert(!opts); - opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &error_abort); - /* BUG: should reject */ - g_assert_cmpuint(opts_count(opts), ==, 1); - g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 16 * G_BYTE); + opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err); + error_free_or_abort(&err); + g_assert(!opts); qemu_opts_reset(&opts_list_02); } diff --git a/util/qemu-option.c b/util/qemu-option.c index 273d00d485..419f2528b8 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -174,39 +174,24 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp) { - char *postfix; - double sizef; + uint64_t size; + int err; - sizef = strtod(value, &postfix); - if (sizef < 0 || sizef > UINT64_MAX) { + err = qemu_strtosz(value, NULL, &size); + if (err == -ERANGE) { + error_setg(errp, "Value '%s' is too large for parameter '%s'", + value, name); + return; + } + if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a non-negative number below 2^64"); + error_append_hint(errp, "Optional suffix k, M, G, T, P or E means" + " kilo-, mega-, giga-, tera-, peta-\n" + "and exabytes, respectively.\n"); return; } - switch (*postfix) { - case 'T': - sizef *= 1024; - /* fall through */ - case 'G': - sizef *= 1024; - /* fall through */ - case 'M': - sizef *= 1024; - /* fall through */ - case 'K': - case 'k': - sizef *= 1024; - /* fall through */ - case 'b': - case '\0': - *ret = (uint64_t) sizef; - break; - default: - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); - error_append_hint(errp, "You may use k, M, G or T suffixes for " - "kilobytes, megabytes, gigabytes and terabytes.\n"); - return; - } + *ret = size; } bool has_help_option(const char *param)