[PULL 17/31] migration: Add a qdev property for StrOrNull

Peter Xu posted 31 patches 1 month, 2 weeks ago
Maintainers: Richard Henderson <richard.henderson@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, Markus Armbruster <armbru@redhat.com>, Michael Roth <michael.roth@amd.com>, Peter Xu <peterx@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Fabiano Rosas <farosas@suse.de>, Mark Kanda <mark.kanda@oracle.com>, Ben Chaney <bchaney@akamai.com>, Eric Blake <eblake@redhat.com>, John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>, Laurent Vivier <lvivier@redhat.com>
[PULL 17/31] migration: Add a qdev property for StrOrNull
Posted by Peter Xu 1 month, 2 weeks ago
From: Fabiano Rosas <farosas@suse.de>

The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
was done about eight years ago so the migration code could make use of
qdev properties to define the defaults for the migration parameters
and to be able to expose migration knobs for debugging via the
'-global migration' command line option.

Due to unrelated historical reasons, three of the migration parameters
(TLS options) received different types when used via the
query-migrate-parameters QMP command than with the
migrate-set-parameters command. This has created a lot of duplication
in the migration code and in the QAPI documentation because the whole
of MigrationParameters had to be duplicated as well.

The migration code is now being fixed to remove the duplication and
for that to happen the offending fields need to be reconciled into a
single type. The StrOrNull type is going to be used.

To keep the command line compatibility, the parameters need to
continue being exposed via qdev properties accessible from the command
line. Introduce a qdev property StrOrNull just for that.

Note that this code is being kept in migration/options.c as this
version of StrOrNull doesn't need to handle QNULL because it was never
a valid option in the previous command line, which took a string.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
Acked-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/r/20251215220041.12657-4-farosas@suse.de
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 migration/options.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/migration/options.c b/migration/options.c
index ea19b2c7cd..d55f3104be 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -83,6 +83,11 @@
 #define DEFINE_PROP_MIG_CAP(name, x)             \
     DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
 
+const PropertyInfo qdev_prop_StrOrNull;
+#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field)                  \
+    DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
+                .set_default = true)
+
 #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD     1000    /* milliseconds */
 #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT            1       /* MB/s */
 
@@ -208,6 +213,68 @@ const Property migration_properties[] = {
 };
 const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
 
+static void get_StrOrNull(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    const Property *prop = opaque;
+    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
+    StrOrNull *str_or_null = *ptr;
+
+    if (!str_or_null) {
+        str_or_null = g_new0(StrOrNull, 1);
+        str_or_null->type = QTYPE_QSTRING;
+        str_or_null->u.s = g_strdup("");
+    } else {
+        /* the setter doesn't allow QNULL */
+        assert(str_or_null->type != QTYPE_QNULL);
+    }
+    visit_type_str(v, name, &str_or_null->u.s, errp);
+}
+
+static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    const Property *prop = opaque;
+    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
+    StrOrNull *str_or_null = g_new0(StrOrNull, 1);
+
+    /*
+     * Only str to keep compatibility, QNULL was never used via
+     * command line.
+     */
+    str_or_null->type = QTYPE_QSTRING;
+    if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
+        return;
+    }
+
+    qapi_free_StrOrNull(*ptr);
+    *ptr = str_or_null;
+}
+
+static void release_StrOrNull(Object *obj, const char *name, void *opaque)
+{
+    const Property *prop = opaque;
+    qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
+}
+
+static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
+{
+    object_property_set_default_str(op, "");
+}
+
+/*
+ * String property like qdev_prop_string, except it's backed by a
+ * StrOrNull instead of a char *.  This is intended for
+ * TYPE_MIGRATION's TLS options.
+ */
+const PropertyInfo qdev_prop_StrOrNull = {
+    .type  = "StrOrNull",
+    .get = get_StrOrNull,
+    .set = set_StrOrNull,
+    .release = release_StrOrNull,
+    .set_default_value = set_default_value_tls_opt,
+};
+
 bool migrate_auto_converge(void)
 {
     MigrationState *s = migrate_get_current();
-- 
2.50.1
Re: [PULL 17/31] migration: Add a qdev property for StrOrNull
Posted by Peter Maydell 2 weeks, 3 days ago
On Tue, 23 Dec 2025 at 14:32, Peter Xu <peterx@redhat.com> wrote:
>
> From: Fabiano Rosas <farosas@suse.de>
>
> The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
> was done about eight years ago so the migration code could make use of
> qdev properties to define the defaults for the migration parameters
> and to be able to expose migration knobs for debugging via the
> '-global migration' command line option.
>
> Due to unrelated historical reasons, three of the migration parameters
> (TLS options) received different types when used via the
> query-migrate-parameters QMP command than with the
> migrate-set-parameters command. This has created a lot of duplication
> in the migration code and in the QAPI documentation because the whole
> of MigrationParameters had to be duplicated as well.
>
> The migration code is now being fixed to remove the duplication and
> for that to happen the offending fields need to be reconciled into a
> single type. The StrOrNull type is going to be used.
>
> To keep the command line compatibility, the parameters need to
> continue being exposed via qdev properties accessible from the command
> line. Introduce a qdev property StrOrNull just for that.
>
> Note that this code is being kept in migration/options.c as this
> version of StrOrNull doesn't need to handle QNULL because it was never
> a valid option in the previous command line, which took a string.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> Acked-by: Peter Xu <peterx@redhat.com>
> Link: https://lore.kernel.org/r/20251215220041.12657-4-farosas@suse.de
> Signed-off-by: Peter Xu <peterx@redhat.com>

Coverity also suspects a leak in the get function (CID 1643920):

> +static void get_StrOrNull(Object *obj, Visitor *v, const char *name,
> +                          void *opaque, Error **errp)
> +{
> +    const Property *prop = opaque;
> +    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
> +    StrOrNull *str_or_null = *ptr;
> +
> +    if (!str_or_null) {
> +        str_or_null = g_new0(StrOrNull, 1);

We allocate memory here, but we never pass this pointer
on to anybody else, and we don't free it either.

> +        str_or_null->type = QTYPE_QSTRING;
> +        str_or_null->u.s = g_strdup("");
> +    } else {
> +        /* the setter doesn't allow QNULL */
> +        assert(str_or_null->type != QTYPE_QNULL);
> +    }
> +    visit_type_str(v, name, &str_or_null->u.s, errp);
> +}
> +

thanks
-- PMM
Re: [PULL 17/31] migration: Add a qdev property for StrOrNull
Posted by Fabiano Rosas 2 weeks, 3 days ago
Peter Maydell <peter.maydell@linaro.org> writes:

> On Tue, 23 Dec 2025 at 14:32, Peter Xu <peterx@redhat.com> wrote:
>>
>> From: Fabiano Rosas <farosas@suse.de>
>>
>> The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
>> was done about eight years ago so the migration code could make use of
>> qdev properties to define the defaults for the migration parameters
>> and to be able to expose migration knobs for debugging via the
>> '-global migration' command line option.
>>
>> Due to unrelated historical reasons, three of the migration parameters
>> (TLS options) received different types when used via the
>> query-migrate-parameters QMP command than with the
>> migrate-set-parameters command. This has created a lot of duplication
>> in the migration code and in the QAPI documentation because the whole
>> of MigrationParameters had to be duplicated as well.
>>
>> The migration code is now being fixed to remove the duplication and
>> for that to happen the offending fields need to be reconciled into a
>> single type. The StrOrNull type is going to be used.
>>
>> To keep the command line compatibility, the parameters need to
>> continue being exposed via qdev properties accessible from the command
>> line. Introduce a qdev property StrOrNull just for that.
>>
>> Note that this code is being kept in migration/options.c as this
>> version of StrOrNull doesn't need to handle QNULL because it was never
>> a valid option in the previous command line, which took a string.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> Acked-by: Peter Xu <peterx@redhat.com>
>> Link: https://lore.kernel.org/r/20251215220041.12657-4-farosas@suse.de
>> Signed-off-by: Peter Xu <peterx@redhat.com>
>
> Coverity also suspects a leak in the get function (CID 1643920):
>
>> +static void get_StrOrNull(Object *obj, Visitor *v, const char *name,
>> +                          void *opaque, Error **errp)
>> +{
>> +    const Property *prop = opaque;
>> +    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
>> +    StrOrNull *str_or_null = *ptr;
>> +
>> +    if (!str_or_null) {
>> +        str_or_null = g_new0(StrOrNull, 1);
>
> We allocate memory here, but we never pass this pointer
> on to anybody else, and we don't free it either.
>

Thank you, I'll look into both issues right away.
Re: [PULL 17/31] migration: Add a qdev property for StrOrNull
Posted by Peter Maydell 2 weeks, 3 days ago
On Tue, 23 Dec 2025 at 14:32, Peter Xu <peterx@redhat.com> wrote:
>
> From: Fabiano Rosas <farosas@suse.de>
>
> The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
> was done about eight years ago so the migration code could make use of
> qdev properties to define the defaults for the migration parameters
> and to be able to expose migration knobs for debugging via the
> '-global migration' command line option.
>
> Due to unrelated historical reasons, three of the migration parameters
> (TLS options) received different types when used via the
> query-migrate-parameters QMP command than with the
> migrate-set-parameters command. This has created a lot of duplication
> in the migration code and in the QAPI documentation because the whole
> of MigrationParameters had to be duplicated as well.
>
> The migration code is now being fixed to remove the duplication and
> for that to happen the offending fields need to be reconciled into a
> single type. The StrOrNull type is going to be used.
>
> To keep the command line compatibility, the parameters need to
> continue being exposed via qdev properties accessible from the command
> line. Introduce a qdev property StrOrNull just for that.
>
> Note that this code is being kept in migration/options.c as this
> version of StrOrNull doesn't need to handle QNULL because it was never
> a valid option in the previous command line, which took a string.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> Acked-by: Peter Xu <peterx@redhat.com>
> Link: https://lore.kernel.org/r/20251215220041.12657-4-farosas@suse.de
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
>  migration/options.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)

Hi; Coverity thinks there's a memory leak in this code
(CID 1643919). Now I know Coverity gets easily confused about
our visitor patterns, and I don't myself know the way they're
supposed to handle ownership of memory, so this should be
checked by somebody who does before adding any extra calls
to free. That said:

> +static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
> +                          void *opaque, Error **errp)
> +{
> +    const Property *prop = opaque;
> +    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
> +    StrOrNull *str_or_null = g_new0(StrOrNull, 1);
> +
> +    /*
> +     * Only str to keep compatibility, QNULL was never used via
> +     * command line.
> +     */
> +    str_or_null->type = QTYPE_QSTRING;
> +    if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
> +        return;

In this error-return code path, we don't seem to hand the
"str_or_null" pointer on to anybody, and we don't free it
either -- does this leak what we just allocated with g_new0() ?

> +    }
> +
> +    qapi_free_StrOrNull(*ptr);
> +    *ptr = str_or_null;
> +}

thanks
-- PMM