diff mbox

[v22,06/25] add convert functions between QEMUOptionParameter to QemuOpts

Message ID 1394436721-21812-7-git-send-email-cyliu@suse.com
State New
Headers show

Commit Message

Chunyan Liu March 10, 2014, 7:31 a.m. UTC
Add two temp convert functions between QEMUOptionParameter to QemuOpts, so that
next patch can use it. It will simplify next patch for easier review.

Signed-off-by: Chunyan Liu <cyliu@suse.com>
---
 include/qemu/option.h |   2 +
 util/qemu-option.c    | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

Comments

Eric Blake March 11, 2014, 4:46 a.m. UTC | #1
On 03/10/2014 01:31 AM, Chunyan Liu wrote:
> Add two temp convert functions between QEMUOptionParameter to QemuOpts, so that
> next patch can use it. It will simplify next patch for easier review.
> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> ---
>  include/qemu/option.h |   2 +
>  util/qemu-option.c    | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 107 insertions(+)
> 

> +
> +/* convert QEMUOptionParameter to QemuOpts */
> +QemuOptsList *params_to_opts(QEMUOptionParameter *list)
> +{
> +    QemuOptsList *opts = NULL;
> +    size_t num_opts, i = 0;
> +
> +    if (!list) {
> +        return NULL;
> +    }
> +
> +    num_opts = count_option_parameters(list);
> +    opts = g_malloc0(sizeof(QemuOptsList) +
> +                     (num_opts + 1) * sizeof(QemuOptDesc));
> +    QTAILQ_INIT(&opts->head);
> +    opts->desc[i].name = NULL;

Dead assignment to NULL, thanks to the g_malloc0 above.

> +
> +    while (list && list->name) {
> +        opts->desc[i].name = g_strdup(list->name);
> +        opts->desc[i].help = g_strdup(list->help);
> +        switch (list->type) {
> +        case OPT_FLAG:
> +            opts->desc[i].type = QEMU_OPT_BOOL;
> +            opts->desc[i].def_value_str = list->value.n ? "on" : "off";

Ouch.  The pointer used here points to constant memory...

> +            break;
> +
> +        case OPT_NUMBER:
> +            opts->desc[i].type = QEMU_OPT_NUMBER;
> +            if (list->value.n) {
> +                opts->desc[i].def_value_str =
> +                    g_strdup_printf("%" PRIu64, list->value.n);

...while the pointer used here points to heap memory.  Yet I see nothing
in the struct that you use to track whether to free the string or not,
which means this is more likely a memory leak, but also a potential for
a crash during an errant call to g_free().  You absolutely must manage
the memory correctly, if you are going to conditionally heap-allocate
def_value_str.

For the sake of conversions between the two types, may I suggest an idea:
in 'struct QemuOpt', add a char[24] buffer (that's large enough to hold
the maximum stringized uint value).  Then, instead of malloc'ing memory
with g_strdup_printf, you instead format integers in place.  You've
already malloc'd the size for the QemuOpt, and now the string
representation also fits within that space without needing a secondary
malloc.

Whether or not you end up keeping the stringizing buffer permanently
part of QemuOpt, or delete it after you delete QEMUOptionParameter,
remains to be seen at the end of the series.

> +        case OPT_STRING:
> +            opts->desc[i].type = QEMU_OPT_STRING;
> +            opts->desc[i].def_value_str = g_strdup(list->value.s);

Here, just declare that your temporary QemuOptsList result from the
function has a shorter lifetime than the input QemuOptionParameter, and
set the def_value_str pointer to the original list->value.s instead of
duplicating it.  Then, you are back to the situation where freeing the
temporary QemuOptsList doesn't leak and doesn't risk double frees.


> +QEMUOptionParameter *opts_to_params(QemuOpts *opts)
> +{
> +    QEMUOptionParameter *dest = NULL;
> +    QemuOptDesc *desc;
> +    size_t num_opts, i = 0;
> +    const char *tmp;
> +
> +    if (!opts || !opts->list || !opts->list->desc) {
> +        return NULL;
> +    }
> +
> +    num_opts = count_opts_list(opts->list);
> +    dest = g_malloc0((num_opts + 1) * sizeof(QEMUOptionParameter));
> +    dest[i].name = NULL;
> +
> +    desc = opts->list->desc;
> +    while (desc && desc->name) {
> +        dest[i].name = g_strdup(desc->name);
> +        dest[i].help = g_strdup(desc->help);

I didn't research QEMUOptionParameter close enough to know if you will
be causing any memory leaks on the reverse conversion - but since the
end goal of the series is to delete QEMUOptionParameter, this method
will eventually disappear, so I guess I could live with leaks here
(although it would be nice to document it in the commit message, if you
do indeed leak).
diff mbox

Patch

diff --git a/include/qemu/option.h b/include/qemu/option.h
index de4912a..a6aca59 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -170,4 +170,6 @@  int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
 QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
 void qemu_opts_free(QemuOptsList *list);
 void qemu_opts_print_help(QemuOptsList *list);
+QEMUOptionParameter *opts_to_params(QemuOpts *opts);
+QemuOptsList *params_to_opts(QEMUOptionParameter *list);
 #endif
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 2c450e0..e05b126 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1464,3 +1464,108 @@  void qemu_opts_print_help(QemuOptsList *list)
                list->desc[i].help : "");
     }
 }
+
+/* convert QEMUOptionParameter to QemuOpts */
+QemuOptsList *params_to_opts(QEMUOptionParameter *list)
+{
+    QemuOptsList *opts = NULL;
+    size_t num_opts, i = 0;
+
+    if (!list) {
+        return NULL;
+    }
+
+    num_opts = count_option_parameters(list);
+    opts = g_malloc0(sizeof(QemuOptsList) +
+                     (num_opts + 1) * sizeof(QemuOptDesc));
+    QTAILQ_INIT(&opts->head);
+    opts->desc[i].name = NULL;
+
+    while (list && list->name) {
+        opts->desc[i].name = g_strdup(list->name);
+        opts->desc[i].help = g_strdup(list->help);
+        switch (list->type) {
+        case OPT_FLAG:
+            opts->desc[i].type = QEMU_OPT_BOOL;
+            opts->desc[i].def_value_str = list->value.n ? "on" : "off";
+            break;
+
+        case OPT_NUMBER:
+            opts->desc[i].type = QEMU_OPT_NUMBER;
+            if (list->value.n) {
+                opts->desc[i].def_value_str =
+                    g_strdup_printf("%" PRIu64, list->value.n);
+            }
+            break;
+
+        case OPT_SIZE:
+            opts->desc[i].type = QEMU_OPT_SIZE;
+            if (list->value.n) {
+                opts->desc[i].def_value_str =
+                    g_strdup_printf("%" PRIu64, list->value.n);
+            }
+            break;
+
+        case OPT_STRING:
+            opts->desc[i].type = QEMU_OPT_STRING;
+            opts->desc[i].def_value_str = g_strdup(list->value.s);
+            break;
+        }
+
+        i++;
+        list++;
+        opts->desc[i].name = NULL;
+    }
+
+    return opts;
+}
+
+QEMUOptionParameter *opts_to_params(QemuOpts *opts)
+{
+    QEMUOptionParameter *dest = NULL;
+    QemuOptDesc *desc;
+    size_t num_opts, i = 0;
+    const char *tmp;
+
+    if (!opts || !opts->list || !opts->list->desc) {
+        return NULL;
+    }
+
+    num_opts = count_opts_list(opts->list);
+    dest = g_malloc0((num_opts + 1) * sizeof(QEMUOptionParameter));
+    dest[i].name = NULL;
+
+    desc = opts->list->desc;
+    while (desc && desc->name) {
+        dest[i].name = g_strdup(desc->name);
+        dest[i].help = g_strdup(desc->help);
+        switch (desc->type) {
+        case QEMU_OPT_STRING:
+            dest[i].type = OPT_STRING;
+            tmp = qemu_opt_get(opts, desc->name);
+            dest[i].value.s = g_strdup(tmp);
+            break;
+
+        case QEMU_OPT_BOOL:
+            dest[i].type = OPT_FLAG;
+            dest[i].value.n = qemu_opt_get_bool(opts, desc->name, 0) ? 1 : 0;
+            break;
+
+        case QEMU_OPT_NUMBER:
+            dest[i].type = OPT_NUMBER;
+            dest[i].value.n = qemu_opt_get_number(opts, desc->name, 0);
+            break;
+
+        case QEMU_OPT_SIZE:
+            dest[i].type = OPT_SIZE;
+            dest[i].value.n = qemu_opt_get_size(opts, desc->name, 0);
+            break;
+        }
+
+        i++;
+        desc++;
+        dest[i].name = NULL;
+    }
+
+    return dest;
+}