Commit 75cdcd15 authored by Markus Armbruster's avatar Markus Armbruster
Browse files

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: default avatarMarkus Armbruster <armbru@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Message-Id: <1487708048-2131-25-git-send-email-armbru@redhat.com>
parent f46bfdbf
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -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);
}
+13 −28
Original line number Diff line number Diff line
@@ -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) {
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
                   "a non-negative number below 2^64");
    err = qemu_strtosz(value, NULL, &size);
    if (err == -ERANGE) {
        error_setg(errp, "Value '%s' is too large for parameter '%s'",
                   value, name);
        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");
    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;
    }
    *ret = size;
}

bool has_help_option(const char *param)