diff mbox series

[1/1] qom: fix setting of array properties

Message ID 20230904162544.2388037-2-berrange@redhat.com
State New
Headers show
Series qom: fix setting of qdev array properties | expand

Commit Message

Daniel P. Berrangé Sept. 4, 2023, 4:25 p.m. UTC
DEFINE_PROP_ARRAY() creates a property 'len-$ARRAY-PROP-NAME'
which, when set, will create a sequence of '$ARRAY-PROP-NAME[N]'
properties.

This only works if the 'len-$ARRAY-PROP-NAME' property is
set first, and the array elements afterwards. Historically
this required the user to set correct ordering and QemuOpts
traversal would preserve that ordering. With QemuOpts now
converted to QDict, iteration ordering is undefined. Thus
to keep array properties working, we iterate over the QDict
twice.

Doing this in QOM is a bit of a layering violation since
DEFINE_PROP_ARRAY is part of QDev, but it is the simplest
option to preserve backwards compatibility, without ripple
effects across any other part of QEMU.

Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1090
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 qom/object_interfaces.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
diff mbox series

Patch

diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index 7d31589b04..6aaaf42ffc 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -51,7 +51,37 @@  static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
     if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
         return;
     }
+
+    /* Layering violation here...
+     *
+     * DEFINE_PROP_ARRAY() creates a property 'len-$ARRAY-PROP-NAME'
+     * which, when set, will create a sequence of '$ARRAY-PROP-NAME[N]'
+     * properties.
+     *
+     * This only works if the 'len-$ARRAY-PROP-NAME' property is
+     * set first, and the array elements afterwards. Historically
+     * this required the user to get correct ordering and QemuOpts
+     * traversal would preserve that ordering. With QemuOpts now
+     * converted to QDict, iteration ordering is undefined. Thus
+     * to keep array properties working, we iterate over the QDict
+     * twice.
+     */
+
+    /* First the props that control array property length */
     for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
+        if (!g_str_has_prefix(e->key, "len-")) {
+            continue;
+        }
+        if (!object_property_set(obj, e->key, v, errp)) {
+            goto out;
+        }
+    }
+
+    /* Then any other normal properties */
+    for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
+        if (g_str_has_prefix(e->key, "len-")) {
+            continue;
+        }
         if (!object_property_set(obj, e->key, v, errp)) {
             goto out;
         }