* [PATCH v3 1/8] qom/object.c: introduce object_alias_get_targetp() lookup function
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias() Mark Cave-Ayland
` (6 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
This will be used later to add support for alias class properties.
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
---
qom/object.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/qom/object.c b/qom/object.c
index 85bbd7f9fe..a904f53ed6 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -3043,13 +3043,20 @@ typedef struct {
char *target_name;
} AliasProperty;
+static Object **
+object_alias_get_targetp(Object *obj, AliasProperty *lprop)
+{
+ return &lprop->target_obj;
+}
+
static void property_get_alias(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
AliasProperty *prop = opaque;
+ Object **target_obj = object_alias_get_targetp(obj, prop);
Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
- object_property_get(prop->target_obj, prop->target_name, alias_v, errp);
+ object_property_get(*target_obj, prop->target_name, alias_v, errp);
visit_free(alias_v);
}
@@ -3057,9 +3064,10 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
AliasProperty *prop = opaque;
+ Object **target_obj = object_alias_get_targetp(obj, prop);
Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
- object_property_set(prop->target_obj, prop->target_name, alias_v, errp);
+ object_property_set(*target_obj, prop->target_name, alias_v, errp);
visit_free(alias_v);
}
@@ -3067,8 +3075,9 @@ static Object *property_resolve_alias(Object *obj, void *opaque,
const char *part)
{
AliasProperty *prop = opaque;
+ Object **target_obj = object_alias_get_targetp(obj, prop);
- return object_resolve_path_component(prop->target_obj, prop->target_name);
+ return object_resolve_path_component(*target_obj, prop->target_name);
}
static void property_release_alias(Object *obj, const char *name, void *opaque)
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 1/8] qom/object.c: introduce object_alias_get_targetp() lookup function Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-17 8:52 ` Marc-André Lureau
2026-09-02 14:40 ` [PATCH v3 3/8] qom/object.c: introduce object_property_set_alias() function Mark Cave-Ayland
` (5 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
This is eventually intended to be a replacement for object_property_add_alias()
which uses an object property instead of a class property.
With the advent of class properties, it is possible that QOM may attempt to
set or retrieve the value of an unset alias property. Update the existing
property_get_alias() and property_set_alias() functions to use the null visitor
if the alias target has not been set, and property_resolve_alias() to return
NULL for the same case.
This ensures that unset class alias properties accessed e.g. via the monitor do
not cause QEMU to crash.
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
---
include/qom/object.h | 25 +++++++++++
qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
2 files changed, 113 insertions(+), 12 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h
index e24f0a2b2d..96c76975ef 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
const uint64_t *v,
ObjectPropertyFlags flags);
+typedef enum {
+ /* private */
+ OBJ_PROP_ALIAS_CLASS = 0x1,
+} ObjectPropertyAliasFlags;
+
/**
* object_property_add_alias:
* @obj: the object to add a property to
@@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
ObjectProperty *object_property_add_alias(Object *obj, const char *name,
Object *target_obj, const char *target_name);
+/**
+ * object_class_property_add_alias:
+ * @klass: the object class to add a property to
+ * @name: the name of the property
+ * @offset: the offset from the object instance where the object alias is
+ * stored
+ * @target_type: QOM type we expect the alias to resolve to
+ * @target_name: the name of the property on the forwarded object
+ *
+ * Add an alias for a property on an object. This function will add a property
+ * of the same type as the forwarded property.
+ *
+ * Returns: The newly added property on success, or %NULL on failure.
+ */
+ObjectProperty *
+object_class_property_add_alias(ObjectClass *klass, const char *name,
+ ptrdiff_t offset,
+ const char *target_type,
+ const char *target_name);
+
/**
* object_property_add_const_link:
* @obj: the object to add a property to
diff --git a/qom/object.c b/qom/object.c
index a904f53ed6..9a05e189ea 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -34,6 +34,7 @@
#include "qom/qom-qobject.h"
#include "qobject/qbool.h"
#include "qobject/qlist.h"
+#include "qobject/qnull.h"
#include "qobject/qnum.h"
#include "qobject/qstring.h"
#include "qemu/error-report.h"
@@ -3039,14 +3040,22 @@ object_class_static_property_add_uint64_ptr(ObjectClass *klass,
}
typedef struct {
- Object *target_obj;
+ union {
+ Object *target_obj; /* if !OBJ_PROP_ALIAS_CLASS */
+ ptrdiff_t offset; /* if OBJ_PROP_ALIAS_CLASS */
+ };
char *target_name;
+ ObjectPropertyAliasFlags flags;
} AliasProperty;
static Object **
-object_alias_get_targetp(Object *obj, AliasProperty *lprop)
+object_alias_get_targetp(Object *obj, AliasProperty *aprop)
{
- return &lprop->target_obj;
+ if (aprop->flags & OBJ_PROP_ALIAS_CLASS) {
+ return (void *)obj + aprop->offset;
+ } else {
+ return &aprop->target_obj;
+ }
}
static void property_get_alias(Object *obj, Visitor *v, const char *name,
@@ -3054,10 +3063,18 @@ static void property_get_alias(Object *obj, Visitor *v, const char *name,
{
AliasProperty *prop = opaque;
Object **target_obj = object_alias_get_targetp(obj, prop);
- Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
- object_property_get(*target_obj, prop->target_name, alias_v, errp);
- visit_free(alias_v);
+ if (*target_obj) {
+ Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
+
+ object_property_get(*target_obj, prop->target_name, alias_v, errp);
+ visit_free(alias_v);
+ } else {
+ QNull *null = NULL;
+
+ visit_type_null(v, NULL, &null, errp);
+ qnull_unref(null);
+ };
}
static void property_set_alias(Object *obj, Visitor *v, const char *name,
@@ -3065,10 +3082,18 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name,
{
AliasProperty *prop = opaque;
Object **target_obj = object_alias_get_targetp(obj, prop);
- Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
- object_property_set(*target_obj, prop->target_name, alias_v, errp);
- visit_free(alias_v);
+ if (*target_obj) {
+ Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
+
+ object_property_set(*target_obj, prop->target_name, alias_v, errp);
+ visit_free(alias_v);
+ } else {
+ QNull *null = NULL;
+
+ visit_type_null(v, NULL, &null, errp);
+ qnull_unref(null);
+ }
}
static Object *property_resolve_alias(Object *obj, void *opaque,
@@ -3077,15 +3102,21 @@ static Object *property_resolve_alias(Object *obj, void *opaque,
AliasProperty *prop = opaque;
Object **target_obj = object_alias_get_targetp(obj, prop);
- return object_resolve_path_component(*target_obj, prop->target_name);
+ if (*target_obj) {
+ return object_resolve_path_component(*target_obj, prop->target_name);
+ } else {
+ return NULL;
+ }
}
static void property_release_alias(Object *obj, const char *name, void *opaque)
{
AliasProperty *prop = opaque;
- g_free(prop->target_name);
- g_free(prop);
+ if (!(prop->flags & OBJ_PROP_ALIAS_CLASS)) {
+ g_free(prop->target_name);
+ g_free(prop);
+ }
}
ObjectProperty *
@@ -3110,6 +3141,7 @@ object_property_add_alias(Object *obj, const char *name,
prop = g_malloc(sizeof(*prop));
prop->target_obj = target_obj;
prop->target_name = g_strdup(target_name);
+ prop->flags = 0;
op = object_property_add(obj, name, prop_type,
property_get_alias,
@@ -3126,6 +3158,50 @@ object_property_add_alias(Object *obj, const char *name,
return op;
}
+ObjectProperty *
+object_class_property_add_alias(ObjectClass *klass, const char *name,
+ ptrdiff_t offset,
+ const char *target_type,
+ const char *target_name)
+{
+ AliasProperty *prop;
+ ObjectProperty *op;
+ ObjectProperty *target_prop;
+ ObjectClass *target_class;
+ g_autofree char *prop_type = NULL;
+
+ target_class = object_class_by_name(target_type);
+ assert(target_class);
+ target_prop = object_class_property_find(target_class, target_name);
+ assert(target_prop);
+
+ if (object_property_is_child(target_prop)) {
+ prop_type = g_strdup_printf("link%s",
+ target_prop->type + strlen("child"));
+ } else {
+ prop_type = g_strdup(target_prop->type);
+ }
+
+ prop = g_malloc(sizeof(*prop));
+ prop->offset = offset;
+ prop->target_name = g_strdup(target_name);
+ prop->flags = OBJ_PROP_ALIAS_CLASS;
+
+ op = object_class_property_add(klass, name, prop_type,
+ property_get_alias,
+ property_set_alias,
+ property_release_alias,
+ prop);
+ op->resolve = property_resolve_alias;
+ if (target_prop->defval) {
+ op->defval = qobject_ref(target_prop->defval);
+ }
+
+ object_class_property_set_description(klass, op->name,
+ target_prop->description);
+ return op;
+}
+
void object_property_set_description(Object *obj, const char *name,
const char *description)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-02 14:40 ` [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias() Mark Cave-Ayland
@ 2026-09-17 8:52 ` Marc-André Lureau
2026-09-18 8:38 ` Mark Cave-Ayland
0 siblings, 1 reply; 15+ messages in thread
From: Marc-André Lureau @ 2026-09-17 8:52 UTC (permalink / raw)
To: Mark Cave-Ayland
Cc: pbonzini, richard.henderson, mst, mtosatti, armbru, qemu-devel
Hi
On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
<mark.caveayland@nutanix.com> wrote:
>
> This is eventually intended to be a replacement for object_property_add_alias()
> which uses an object property instead of a class property.
>
> With the advent of class properties, it is possible that QOM may attempt to
> set or retrieve the value of an unset alias property. Update the existing
> property_get_alias() and property_set_alias() functions to use the null visitor
> if the alias target has not been set, and property_resolve_alias() to return
> NULL for the same case.
>
> This ensures that unset class alias properties accessed e.g. via the monitor do
> not cause QEMU to crash.
>
> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
> ---
> include/qom/object.h | 25 +++++++++++
> qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
> 2 files changed, 113 insertions(+), 12 deletions(-)
>
> diff --git a/include/qom/object.h b/include/qom/object.h
> index e24f0a2b2d..96c76975ef 100644
> --- a/include/qom/object.h
> +++ b/include/qom/object.h
> @@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
> const uint64_t *v,
> ObjectPropertyFlags flags);
>
> +typedef enum {
> + /* private */
> + OBJ_PROP_ALIAS_CLASS = 0x1,
> +} ObjectPropertyAliasFlags;
> +
> /**
> * object_property_add_alias:
> * @obj: the object to add a property to
> @@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
> ObjectProperty *object_property_add_alias(Object *obj, const char *name,
> Object *target_obj, const char *target_name);
>
> +/**
> + * object_class_property_add_alias:
> + * @klass: the object class to add a property to
> + * @name: the name of the property
> + * @offset: the offset from the object instance where the object alias is
> + * stored
> + * @target_type: QOM type we expect the alias to resolve to
> + * @target_name: the name of the property on the forwarded object
> + *
> + * Add an alias for a property on an object. This function will add a property
> + * of the same type as the forwarded property.
> + *
> + * Returns: The newly added property on success, or %NULL on failure.
actually, it assert() on error and never returns NULL.
> + */
> +ObjectProperty *
> +object_class_property_add_alias(ObjectClass *klass, const char *name,
> + ptrdiff_t offset,
> + const char *target_type,
> + const char *target_name);
> +
> /**
> * object_property_add_const_link:
> * @obj: the object to add a property to
> diff --git a/qom/object.c b/qom/object.c
> index a904f53ed6..9a05e189ea 100644
> --- a/qom/object.c
> +++ b/qom/object.c
> @@ -34,6 +34,7 @@
> #include "qom/qom-qobject.h"
> #include "qobject/qbool.h"
> #include "qobject/qlist.h"
> +#include "qobject/qnull.h"
> #include "qobject/qnum.h"
> #include "qobject/qstring.h"
> #include "qemu/error-report.h"
> @@ -3039,14 +3040,22 @@ object_class_static_property_add_uint64_ptr(ObjectClass *klass,
> }
>
> typedef struct {
> - Object *target_obj;
> + union {
> + Object *target_obj; /* if !OBJ_PROP_ALIAS_CLASS */
> + ptrdiff_t offset; /* if OBJ_PROP_ALIAS_CLASS */
> + };
> char *target_name;
> + ObjectPropertyAliasFlags flags;
> } AliasProperty;
>
> static Object **
> -object_alias_get_targetp(Object *obj, AliasProperty *lprop)
> +object_alias_get_targetp(Object *obj, AliasProperty *aprop)
> {
> - return &lprop->target_obj;
> + if (aprop->flags & OBJ_PROP_ALIAS_CLASS) {
> + return (void *)obj + aprop->offset;
> + } else {
> + return &aprop->target_obj;
> + }
> }
>
> static void property_get_alias(Object *obj, Visitor *v, const char *name,
> @@ -3054,10 +3063,18 @@ static void property_get_alias(Object *obj, Visitor *v, const char *name,
> {
> AliasProperty *prop = opaque;
> Object **target_obj = object_alias_get_targetp(obj, prop);
> - Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>
> - object_property_get(*target_obj, prop->target_name, alias_v, errp);
> - visit_free(alias_v);
> + if (*target_obj) {
> + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
> +
> + object_property_get(*target_obj, prop->target_name, alias_v, errp);
> + visit_free(alias_v);
> + } else {
> + QNull *null = NULL;
> +
> + visit_type_null(v, NULL, &null, errp);
> + qnull_unref(null);
> + };
extra ;
> }
>
> static void property_set_alias(Object *obj, Visitor *v, const char *name,
> @@ -3065,10 +3082,18 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name,
> {
> AliasProperty *prop = opaque;
> Object **target_obj = object_alias_get_targetp(obj, prop);
> - Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>
> - object_property_set(*target_obj, prop->target_name, alias_v, errp);
> - visit_free(alias_v);
> + if (*target_obj) {
> + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
> +
> + object_property_set(*target_obj, prop->target_name, alias_v, errp);
> + visit_free(alias_v);
> + } else {
> + QNull *null = NULL;
> +
> + visit_type_null(v, NULL, &null, errp);
> + qnull_unref(null);
Why not return an error?
> + }
> }
>
> static Object *property_resolve_alias(Object *obj, void *opaque,
> @@ -3077,15 +3102,21 @@ static Object *property_resolve_alias(Object *obj, void *opaque,
> AliasProperty *prop = opaque;
> Object **target_obj = object_alias_get_targetp(obj, prop);
>
> - return object_resolve_path_component(*target_obj, prop->target_name);
> + if (*target_obj) {
> + return object_resolve_path_component(*target_obj, prop->target_name);
> + } else {
> + return NULL;
> + }
> }
>
> static void property_release_alias(Object *obj, const char *name, void *opaque)
> {
> AliasProperty *prop = opaque;
>
> - g_free(prop->target_name);
> - g_free(prop);
> + if (!(prop->flags & OBJ_PROP_ALIAS_CLASS)) {
> + g_free(prop->target_name);
> + g_free(prop);
> + }
> }
>
> ObjectProperty *
> @@ -3110,6 +3141,7 @@ object_property_add_alias(Object *obj, const char *name,
> prop = g_malloc(sizeof(*prop));
> prop->target_obj = target_obj;
> prop->target_name = g_strdup(target_name);
> + prop->flags = 0;
>
> op = object_property_add(obj, name, prop_type,
> property_get_alias,
> @@ -3126,6 +3158,50 @@ object_property_add_alias(Object *obj, const char *name,
> return op;
> }
>
> +ObjectProperty *
> +object_class_property_add_alias(ObjectClass *klass, const char *name,
> + ptrdiff_t offset,
> + const char *target_type,
> + const char *target_name)
> +{
> + AliasProperty *prop;
> + ObjectProperty *op;
> + ObjectProperty *target_prop;
> + ObjectClass *target_class;
> + g_autofree char *prop_type = NULL;
> +
> + target_class = object_class_by_name(target_type);
> + assert(target_class);
> + target_prop = object_class_property_find(target_class, target_name);
> + assert(target_prop);
> +
> + if (object_property_is_child(target_prop)) {
> + prop_type = g_strdup_printf("link%s",
> + target_prop->type + strlen("child"));
> + } else {
> + prop_type = g_strdup(target_prop->type);
> + }
> +
> + prop = g_malloc(sizeof(*prop));
> + prop->offset = offset;
> + prop->target_name = g_strdup(target_name);
> + prop->flags = OBJ_PROP_ALIAS_CLASS;
> +
> + op = object_class_property_add(klass, name, prop_type,
> + property_get_alias,
> + property_set_alias,
> + property_release_alias,
> + prop);
> + op->resolve = property_resolve_alias;
> + if (target_prop->defval) {
> + op->defval = qobject_ref(target_prop->defval);
> + }
> +
> + object_class_property_set_description(klass, op->name,
> + target_prop->description);
> + return op;
> +}
> +
> void object_property_set_description(Object *obj, const char *name,
> const char *description)
> {
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-17 8:52 ` Marc-André Lureau
@ 2026-09-18 8:38 ` Mark Cave-Ayland
2026-09-18 9:04 ` Markus Armbruster
0 siblings, 1 reply; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-18 8:38 UTC (permalink / raw)
To: Marc-André Lureau
Cc: pbonzini, richard.henderson, mst, mtosatti, armbru, qemu-devel
On 17/09/2026 09:52, Marc-André Lureau wrote:
> Hi
>
> On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
> <mark.caveayland@nutanix.com> wrote:
>>
>> This is eventually intended to be a replacement for object_property_add_alias()
>> which uses an object property instead of a class property.
>>
>> With the advent of class properties, it is possible that QOM may attempt to
>> set or retrieve the value of an unset alias property. Update the existing
>> property_get_alias() and property_set_alias() functions to use the null visitor
>> if the alias target has not been set, and property_resolve_alias() to return
>> NULL for the same case.
>>
>> This ensures that unset class alias properties accessed e.g. via the monitor do
>> not cause QEMU to crash.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
>> ---
>> include/qom/object.h | 25 +++++++++++
>> qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
>> 2 files changed, 113 insertions(+), 12 deletions(-)
>>
>> diff --git a/include/qom/object.h b/include/qom/object.h
>> index e24f0a2b2d..96c76975ef 100644
>> --- a/include/qom/object.h
>> +++ b/include/qom/object.h
>> @@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>> const uint64_t *v,
>> ObjectPropertyFlags flags);
>>
>> +typedef enum {
>> + /* private */
>> + OBJ_PROP_ALIAS_CLASS = 0x1,
>> +} ObjectPropertyAliasFlags;
>> +
>> /**
>> * object_property_add_alias:
>> * @obj: the object to add a property to
>> @@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>> ObjectProperty *object_property_add_alias(Object *obj, const char *name,
>> Object *target_obj, const char *target_name);
>>
>> +/**
>> + * object_class_property_add_alias:
>> + * @klass: the object class to add a property to
>> + * @name: the name of the property
>> + * @offset: the offset from the object instance where the object alias is
>> + * stored
>> + * @target_type: QOM type we expect the alias to resolve to
>> + * @target_name: the name of the property on the forwarded object
>> + *
>> + * Add an alias for a property on an object. This function will add a property
>> + * of the same type as the forwarded property.
>> + *
>> + * Returns: The newly added property on success, or %NULL on failure.
>
> actually, it assert() on error and never returns NULL.
I was able to reproduce this by attempting to add a class alias property
with the same name again, and then started to look at other related
functions do to understand what the behaviour should be. There seems to
be a number of existing issues here:
- object_property_try_add() returns NULL in the case a property cannot
be created (which seems to be only when an attempt to make add a
property that already exists). However since object_property_add()
always passes &error_abort, then QEMU terminates immediately without
returning the NULL.
- object_class_property_add() will currently assert() if an attempt is
made to add a duplicate property: it is fairly trivial to update it to
return the same error that object_property_add() does, however it is
interesting to note that the kernel-doc states that
error_setg(&error_abort, ...) should NOT be used. However in this case
it appears to return a genuinely helpful message which I think is
worth keeping.
- There are several places in qom/object.c that do not check the return
value of object_property_add() / object_class_property_add() such as
object_add_link_prop(), object_property_add_alias() which could
potentially dereference a NULL pointer.
It feels like the assumption is actually that these functions will
&error_abort rather than returning NULL as indicated by the kernel-doc.
Any thoughts on what we should do here? Ideally we want the same
behaviour between the object_property*() and object_class_property*()
functions to aid the transition.
>> + */
>> +ObjectProperty *
>> +object_class_property_add_alias(ObjectClass *klass, const char *name,
>> + ptrdiff_t offset,
>> + const char *target_type,
>> + const char *target_name);
>> +
>> /**
>> * object_property_add_const_link:
>> * @obj: the object to add a property to
>> diff --git a/qom/object.c b/qom/object.c
>> index a904f53ed6..9a05e189ea 100644
>> --- a/qom/object.c
>> +++ b/qom/object.c
>> @@ -34,6 +34,7 @@
>> #include "qom/qom-qobject.h"
>> #include "qobject/qbool.h"
>> #include "qobject/qlist.h"
>> +#include "qobject/qnull.h"
>> #include "qobject/qnum.h"
>> #include "qobject/qstring.h"
>> #include "qemu/error-report.h"
>> @@ -3039,14 +3040,22 @@ object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>> }
>>
>> typedef struct {
>> - Object *target_obj;
>> + union {
>> + Object *target_obj; /* if !OBJ_PROP_ALIAS_CLASS */
>> + ptrdiff_t offset; /* if OBJ_PROP_ALIAS_CLASS */
>> + };
>> char *target_name;
>> + ObjectPropertyAliasFlags flags;
>> } AliasProperty;
>>
>> static Object **
>> -object_alias_get_targetp(Object *obj, AliasProperty *lprop)
>> +object_alias_get_targetp(Object *obj, AliasProperty *aprop)
>> {
>> - return &lprop->target_obj;
>> + if (aprop->flags & OBJ_PROP_ALIAS_CLASS) {
>> + return (void *)obj + aprop->offset;
>> + } else {
>> + return &aprop->target_obj;
>> + }
>> }
>>
>> static void property_get_alias(Object *obj, Visitor *v, const char *name,
>> @@ -3054,10 +3063,18 @@ static void property_get_alias(Object *obj, Visitor *v, const char *name,
>> {
>> AliasProperty *prop = opaque;
>> Object **target_obj = object_alias_get_targetp(obj, prop);
>> - Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>>
>> - object_property_get(*target_obj, prop->target_name, alias_v, errp);
>> - visit_free(alias_v);
>> + if (*target_obj) {
>> + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>> +
>> + object_property_get(*target_obj, prop->target_name, alias_v, errp);
>> + visit_free(alias_v);
>> + } else {
>> + QNull *null = NULL;
>> +
>> + visit_type_null(v, NULL, &null, errp);
>> + qnull_unref(null);
>> + };
>
> extra ;
Ooops, thanks.
>> }
>>
>> static void property_set_alias(Object *obj, Visitor *v, const char *name,
>> @@ -3065,10 +3082,18 @@ static void property_set_alias(Object *obj, Visitor *v, const char *name,
>> {
>> AliasProperty *prop = opaque;
>> Object **target_obj = object_alias_get_targetp(obj, prop);
>> - Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>>
>> - object_property_set(*target_obj, prop->target_name, alias_v, errp);
>> - visit_free(alias_v);
>> + if (*target_obj) {
>> + Visitor *alias_v = visitor_forward_field(v, prop->target_name, name);
>> +
>> + object_property_set(*target_obj, prop->target_name, alias_v, errp);
>> + visit_free(alias_v);
>> + } else {
>> + QNull *null = NULL;
>> +
>> + visit_type_null(v, NULL, &null, errp);
>> + qnull_unref(null);
>
> Why not return an error?
I think that would make sense in the context of the discussion above.
>> + }
>> }
>>
>> static Object *property_resolve_alias(Object *obj, void *opaque,
>> @@ -3077,15 +3102,21 @@ static Object *property_resolve_alias(Object *obj, void *opaque,
>> AliasProperty *prop = opaque;
>> Object **target_obj = object_alias_get_targetp(obj, prop);
>>
>> - return object_resolve_path_component(*target_obj, prop->target_name);
>> + if (*target_obj) {
>> + return object_resolve_path_component(*target_obj, prop->target_name);
>> + } else {
>> + return NULL;
>> + }
>> }
>>
>> static void property_release_alias(Object *obj, const char *name, void *opaque)
>> {
>> AliasProperty *prop = opaque;
>>
>> - g_free(prop->target_name);
>> - g_free(prop);
>> + if (!(prop->flags & OBJ_PROP_ALIAS_CLASS)) {
>> + g_free(prop->target_name);
>> + g_free(prop);
>> + }
>> }
>>
>> ObjectProperty *
>> @@ -3110,6 +3141,7 @@ object_property_add_alias(Object *obj, const char *name,
>> prop = g_malloc(sizeof(*prop));
>> prop->target_obj = target_obj;
>> prop->target_name = g_strdup(target_name);
>> + prop->flags = 0;
>>
>> op = object_property_add(obj, name, prop_type,
>> property_get_alias,
>> @@ -3126,6 +3158,50 @@ object_property_add_alias(Object *obj, const char *name,
>> return op;
>> }
>>
>> +ObjectProperty *
>> +object_class_property_add_alias(ObjectClass *klass, const char *name,
>> + ptrdiff_t offset,
>> + const char *target_type,
>> + const char *target_name)
>> +{
>> + AliasProperty *prop;
>> + ObjectProperty *op;
>> + ObjectProperty *target_prop;
>> + ObjectClass *target_class;
>> + g_autofree char *prop_type = NULL;
>> +
>> + target_class = object_class_by_name(target_type);
>> + assert(target_class);
>> + target_prop = object_class_property_find(target_class, target_name);
>> + assert(target_prop);
>> +
>> + if (object_property_is_child(target_prop)) {
>> + prop_type = g_strdup_printf("link%s",
>> + target_prop->type + strlen("child"));
>> + } else {
>> + prop_type = g_strdup(target_prop->type);
>> + }
>> +
>> + prop = g_malloc(sizeof(*prop));
>> + prop->offset = offset;
>> + prop->target_name = g_strdup(target_name);
>> + prop->flags = OBJ_PROP_ALIAS_CLASS;
>> +
>> + op = object_class_property_add(klass, name, prop_type,
>> + property_get_alias,
>> + property_set_alias,
>> + property_release_alias,
>> + prop);
>> + op->resolve = property_resolve_alias;
>> + if (target_prop->defval) {
>> + op->defval = qobject_ref(target_prop->defval);
>> + }
>> +
>> + object_class_property_set_description(klass, op->name,
>> + target_prop->description);
>> + return op;
>> +}
>> +
>> void object_property_set_description(Object *obj, const char *name,
>> const char *description)
>> {
>> --
>> 2.43.0
ATB,
Mark.
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-18 8:38 ` Mark Cave-Ayland
@ 2026-09-18 9:04 ` Markus Armbruster
2026-09-21 9:06 ` Daniel P. Berrangé
0 siblings, 1 reply; 15+ messages in thread
From: Markus Armbruster @ 2026-09-18 9:04 UTC (permalink / raw)
To: Mark Cave-Ayland
Cc: Marc-André Lureau, pbonzini, richard.henderson, mst,
mtosatti, qemu-devel
Mark Cave-Ayland <mark.caveayland@nutanix.com> writes:
> On 17/09/2026 09:52, Marc-André Lureau wrote:
>
>> Hi
>> On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
>> <mark.caveayland@nutanix.com> wrote:
>>>
>>> This is eventually intended to be a replacement for object_property_add_alias()
>>> which uses an object property instead of a class property.
>>>
>>> With the advent of class properties, it is possible that QOM may attempt to
>>> set or retrieve the value of an unset alias property. Update the existing
>>> property_get_alias() and property_set_alias() functions to use the null visitor
>>> if the alias target has not been set, and property_resolve_alias() to return
>>> NULL for the same case.
>>>
>>> This ensures that unset class alias properties accessed e.g. via the monitor do
>>> not cause QEMU to crash.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
>>> ---
>>> include/qom/object.h | 25 +++++++++++
>>> qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
>>> 2 files changed, 113 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/include/qom/object.h b/include/qom/object.h
>>> index e24f0a2b2d..96c76975ef 100644
>>> --- a/include/qom/object.h
>>> +++ b/include/qom/object.h
>>> @@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>>> const uint64_t *v,
>>> ObjectPropertyFlags flags);
>>>
>>> +typedef enum {
>>> + /* private */
>>> + OBJ_PROP_ALIAS_CLASS = 0x1,
>>> +} ObjectPropertyAliasFlags;
>>> +
>>> /**
>>> * object_property_add_alias:
>>> * @obj: the object to add a property to
>>> @@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>>> ObjectProperty *object_property_add_alias(Object *obj, const char *name,
>>> Object *target_obj, const char *target_name);
>>>
>>> +/**
>>> + * object_class_property_add_alias:
>>> + * @klass: the object class to add a property to
>>> + * @name: the name of the property
>>> + * @offset: the offset from the object instance where the object alias is
>>> + * stored
>>> + * @target_type: QOM type we expect the alias to resolve to
>>> + * @target_name: the name of the property on the forwarded object
>>> + *
>>> + * Add an alias for a property on an object. This function will add a property
>>> + * of the same type as the forwarded property.
>>> + *
>>> + * Returns: The newly added property on success, or %NULL on failure.
>> actually, it assert() on error and never returns NULL.
>
> I was able to reproduce this by attempting to add a class alias property with the same name again, and then started to look at other related functions do to understand what the behaviour should be. There seems to be a number of existing issues here:
>
> - object_property_try_add() returns NULL in the case a property cannot
> be created (which seems to be only when an attempt to make add a
> property that already exists). However since object_property_add()
> always passes &error_abort, then QEMU terminates immediately without
> returning the NULL.
Convention: when we have a pair of functions FOO_try_BAR() and
FOO_BAR(), the former can fail and the latter cannot. The latter is
useful when failure would be a programming error.
When FOO_try_BAR() sets an Error on failure, FOO_BAR() is a thin wrapper
that passes &error_abort.
We pass &error_abort when failure would be a programming error. It's
more concise than "call then assert it didn't fail". Concise is good.
The wrapper makes calls that cannot fail even more concise. Worth
having only when there are plenty of callers that profit from that.
Someone decided this is the case for object_property_try_add() /
object_property_add().
> - object_class_property_add() will currently assert() if an attempt is
> made to add a duplicate property: it is fairly trivial to update it to
> return the same error that object_property_add() does, however it is
> interesting to note that the kernel-doc states that
> error_setg(&error_abort, ...) should NOT be used. However in this case
> it appears to return a genuinely helpful message which I think is
> worth keeping.
The only difference between object_class_property_add() and
object_property_add() should be where the property is recorded (class
vs. object). In particular, they should treat failure the same way.
This may make object_class_property_try_add() necessary.
> - There are several places in qom/object.c that do not check the
> return value of object_property_add() / object_class_property_add()
> such as object_add_link_prop(), object_property_add_alias() which
> could potentially dereference a NULL pointer.
object_property_add() is specified not to fail, i.e. not to return null.
It's a programming error if it does. Letting the program crash on
programming errors by dereferencing a null pointer is just fine. We can
dress up the crash with assert(obj), but I wouldn't bother.
Use object_property_add() when failure is a programming error. Use
object_property_try_add() and handle the error when it's not.
> It feels like the assumption is actually that these functions will &error_abort rather than returning NULL as indicated by the kernel-doc. Any thoughts on what we should do here? Ideally we want the same behaviour between the object_property*() and object_class_property*() functions to aid the transition.
Hope this helps!
[...]
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-18 9:04 ` Markus Armbruster
@ 2026-09-21 9:06 ` Daniel P. Berrangé
2026-09-21 13:28 ` Markus Armbruster
0 siblings, 1 reply; 15+ messages in thread
From: Daniel P. Berrangé @ 2026-09-21 9:06 UTC (permalink / raw)
To: Markus Armbruster
Cc: Mark Cave-Ayland, Marc-André Lureau, pbonzini,
richard.henderson, mst, mtosatti, qemu-devel
On Fri, Sep 18, 2026 at 11:04:31AM +0200, Markus Armbruster wrote:
> Mark Cave-Ayland <mark.caveayland@nutanix.com> writes:
>
> > On 17/09/2026 09:52, Marc-André Lureau wrote:
> >
> >> Hi
> >> On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
> >> <mark.caveayland@nutanix.com> wrote:
> >>>
> >>> This is eventually intended to be a replacement for object_property_add_alias()
> >>> which uses an object property instead of a class property.
> >>>
> >>> With the advent of class properties, it is possible that QOM may attempt to
> >>> set or retrieve the value of an unset alias property. Update the existing
> >>> property_get_alias() and property_set_alias() functions to use the null visitor
> >>> if the alias target has not been set, and property_resolve_alias() to return
> >>> NULL for the same case.
> >>>
> >>> This ensures that unset class alias properties accessed e.g. via the monitor do
> >>> not cause QEMU to crash.
> >>>
> >>> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
> >>> ---
> >>> include/qom/object.h | 25 +++++++++++
> >>> qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
> >>> 2 files changed, 113 insertions(+), 12 deletions(-)
> >>>
> >>> diff --git a/include/qom/object.h b/include/qom/object.h
> >>> index e24f0a2b2d..96c76975ef 100644
> >>> --- a/include/qom/object.h
> >>> +++ b/include/qom/object.h
> >>> @@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
> >>> const uint64_t *v,
> >>> ObjectPropertyFlags flags);
> >>>
> >>> +typedef enum {
> >>> + /* private */
> >>> + OBJ_PROP_ALIAS_CLASS = 0x1,
> >>> +} ObjectPropertyAliasFlags;
> >>> +
> >>> /**
> >>> * object_property_add_alias:
> >>> * @obj: the object to add a property to
> >>> @@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
> >>> ObjectProperty *object_property_add_alias(Object *obj, const char *name,
> >>> Object *target_obj, const char *target_name);
> >>>
> >>> +/**
> >>> + * object_class_property_add_alias:
> >>> + * @klass: the object class to add a property to
> >>> + * @name: the name of the property
> >>> + * @offset: the offset from the object instance where the object alias is
> >>> + * stored
> >>> + * @target_type: QOM type we expect the alias to resolve to
> >>> + * @target_name: the name of the property on the forwarded object
> >>> + *
> >>> + * Add an alias for a property on an object. This function will add a property
> >>> + * of the same type as the forwarded property.
> >>> + *
> >>> + * Returns: The newly added property on success, or %NULL on failure.
> >> actually, it assert() on error and never returns NULL.
> >
> > I was able to reproduce this by attempting to add a class alias property with the same name again, and then started to look at other related functions do to understand what the behaviour should be. There seems to be a number of existing issues here:
> >
> > - object_property_try_add() returns NULL in the case a property cannot
> > be created (which seems to be only when an attempt to make add a
> > property that already exists). However since object_property_add()
> > always passes &error_abort, then QEMU terminates immediately without
> > returning the NULL.
>
> Convention: when we have a pair of functions FOO_try_BAR() and
> FOO_BAR(), the former can fail and the latter cannot. The latter is
> useful when failure would be a programming error.
>
> When FOO_try_BAR() sets an Error on failure, FOO_BAR() is a thin wrapper
> that passes &error_abort.
>
> We pass &error_abort when failure would be a programming error. It's
> more concise than "call then assert it didn't fail". Concise is good.
>
> The wrapper makes calls that cannot fail even more concise. Worth
> having only when there are plenty of callers that profit from that.
> Someone decided this is the case for object_property_try_add() /
> object_property_add().
>
> > - object_class_property_add() will currently assert() if an attempt is
> > made to add a duplicate property: it is fairly trivial to update it to
> > return the same error that object_property_add() does, however it is
> > interesting to note that the kernel-doc states that
> > error_setg(&error_abort, ...) should NOT be used. However in this case
> > it appears to return a genuinely helpful message which I think is
> > worth keeping.
>
> The only difference between object_class_property_add() and
> object_property_add() should be where the property is recorded (class
> vs. object). In particular, they should treat failure the same way.
>
> This may make object_class_property_try_add() necessary.
IMHO such a method should not exist. A class must have a well-defined
set of properties that is invariant. Any scenario where a
object_class_property_try_add() method could fail would be 100%
repeatable and at the same time a significant programmer error.
When we had properties against objects 'try_add' was passable, as
we're dynamically adding props and different instances can have
different props, even when the same time. This is all a terrible
idea, and ideally object_property_try_add would not exist either
but it is probably more trouble than its worth right now to attempt
removing object_property_try_add. Just don't mirror it into class
properties.
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias()
2026-09-21 9:06 ` Daniel P. Berrangé
@ 2026-09-21 13:28 ` Markus Armbruster
0 siblings, 0 replies; 15+ messages in thread
From: Markus Armbruster @ 2026-09-21 13:28 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: Mark Cave-Ayland, Marc-André Lureau, pbonzini,
richard.henderson, mst, mtosatti, qemu-devel
Daniel P. Berrangé <berrange@redhat.com> writes:
> On Fri, Sep 18, 2026 at 11:04:31AM +0200, Markus Armbruster wrote:
>> Mark Cave-Ayland <mark.caveayland@nutanix.com> writes:
>>
>> > On 17/09/2026 09:52, Marc-André Lureau wrote:
>> >
>> >> Hi
>> >> On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
>> >> <mark.caveayland@nutanix.com> wrote:
>> >>>
>> >>> This is eventually intended to be a replacement for object_property_add_alias()
>> >>> which uses an object property instead of a class property.
>> >>>
>> >>> With the advent of class properties, it is possible that QOM may attempt to
>> >>> set or retrieve the value of an unset alias property. Update the existing
>> >>> property_get_alias() and property_set_alias() functions to use the null visitor
>> >>> if the alias target has not been set, and property_resolve_alias() to return
>> >>> NULL for the same case.
>> >>>
>> >>> This ensures that unset class alias properties accessed e.g. via the monitor do
>> >>> not cause QEMU to crash.
>> >>>
>> >>> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
>> >>> ---
>> >>> include/qom/object.h | 25 +++++++++++
>> >>> qom/object.c | 100 +++++++++++++++++++++++++++++++++++++------
>> >>> 2 files changed, 113 insertions(+), 12 deletions(-)
>> >>>
>> >>> diff --git a/include/qom/object.h b/include/qom/object.h
>> >>> index e24f0a2b2d..96c76975ef 100644
>> >>> --- a/include/qom/object.h
>> >>> +++ b/include/qom/object.h
>> >>> @@ -2263,6 +2263,11 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>> >>> const uint64_t *v,
>> >>> ObjectPropertyFlags flags);
>> >>>
>> >>> +typedef enum {
>> >>> + /* private */
>> >>> + OBJ_PROP_ALIAS_CLASS = 0x1,
>> >>> +} ObjectPropertyAliasFlags;
>> >>> +
>> >>> /**
>> >>> * object_property_add_alias:
>> >>> * @obj: the object to add a property to
>> >>> @@ -2283,6 +2288,26 @@ ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass,
>> >>> ObjectProperty *object_property_add_alias(Object *obj, const char *name,
>> >>> Object *target_obj, const char *target_name);
>> >>>
>> >>> +/**
>> >>> + * object_class_property_add_alias:
>> >>> + * @klass: the object class to add a property to
>> >>> + * @name: the name of the property
>> >>> + * @offset: the offset from the object instance where the object alias is
>> >>> + * stored
>> >>> + * @target_type: QOM type we expect the alias to resolve to
>> >>> + * @target_name: the name of the property on the forwarded object
>> >>> + *
>> >>> + * Add an alias for a property on an object. This function will add a property
>> >>> + * of the same type as the forwarded property.
>> >>> + *
>> >>> + * Returns: The newly added property on success, or %NULL on failure.
>> >> actually, it assert() on error and never returns NULL.
>> >
>> > I was able to reproduce this by attempting to add a class alias property with the same name again, and then started to look at other related functions do to understand what the behaviour should be. There seems to be a number of existing issues here:
>> >
>> > - object_property_try_add() returns NULL in the case a property cannot
>> > be created (which seems to be only when an attempt to make add a
>> > property that already exists). However since object_property_add()
>> > always passes &error_abort, then QEMU terminates immediately without
>> > returning the NULL.
>>
>> Convention: when we have a pair of functions FOO_try_BAR() and
>> FOO_BAR(), the former can fail and the latter cannot. The latter is
>> useful when failure would be a programming error.
>>
>> When FOO_try_BAR() sets an Error on failure, FOO_BAR() is a thin wrapper
>> that passes &error_abort.
>>
>> We pass &error_abort when failure would be a programming error. It's
>> more concise than "call then assert it didn't fail". Concise is good.
>>
>> The wrapper makes calls that cannot fail even more concise. Worth
>> having only when there are plenty of callers that profit from that.
>> Someone decided this is the case for object_property_try_add() /
>> object_property_add().
>>
>> > - object_class_property_add() will currently assert() if an attempt is
>> > made to add a duplicate property: it is fairly trivial to update it to
>> > return the same error that object_property_add() does, however it is
>> > interesting to note that the kernel-doc states that
>> > error_setg(&error_abort, ...) should NOT be used. However in this case
>> > it appears to return a genuinely helpful message which I think is
>> > worth keeping.
>>
>> The only difference between object_class_property_add() and
>> object_property_add() should be where the property is recorded (class
>> vs. object). In particular, they should treat failure the same way.
>>
>> This may make object_class_property_try_add() necessary.
>
> IMHO such a method should not exist. A class must have a well-defined
> set of properties that is invariant. Any scenario where a
> object_class_property_try_add() method could fail would be 100%
> repeatable and at the same time a significant programmer error.
>
>
> When we had properties against objects 'try_add' was passable, as
> we're dynamically adding props and different instances can have
> different props, even when the same time. This is all a terrible
> idea, and ideally object_property_try_add would not exist either
> but it is probably more trouble than its worth right now to attempt
> removing object_property_try_add. Just don't mirror it into class
> properties.
Good points. Work into object.h comments?
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 3/8] qom/object.c: introduce object_property_set_alias() function
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 1/8] qom/object.c: introduce object_alias_get_targetp() lookup function Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 2/8] qom/object.c: introduce object_class_property_add_alias() Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 4/8] hw/i386/pc.c: convert pcspk-audiodev object prop to a class prop Mark Cave-Ayland
` (4 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
This will be used to set the class alias property for a specific object. Note
that this function is only required for class properties, and will assert at
runtime if an attempt is made to use it on an object alias property.
Update the existing property_release_alias() function to reflect the documented
refcount behaviour.
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
---
include/qom/object.h | 17 +++++++++++++++++
qom/object.c | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/include/qom/object.h b/include/qom/object.h
index 96c76975ef..bb65218aa3 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -2308,6 +2308,23 @@ object_class_property_add_alias(ObjectClass *klass, const char *name,
const char *target_type,
const char *target_name);
+/**
+ * object_property_set_alias:
+ * @obj: the object upon which to set the alias property
+ * @name: the name of the alias property
+ * @target_obj: the object to forward property access to
+ *
+ * Set an alias property on an object to point to @target_obj. This is only
+ * required for class properties, and will assert at runtime if used on an
+ * object property.
+ *
+ * This function ensures that @target_obj stays alive as long as @obj exists
+ * by taking a reference if @target_obj is not a child object or an alias on
+ * the same object.
+ */
+void object_property_set_alias(Object *obj, const char *name,
+ Object *target_obj);
+
/**
* object_property_add_const_link:
* @obj: the object to add a property to
diff --git a/qom/object.c b/qom/object.c
index 9a05e189ea..51d21cf1d0 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -3116,6 +3116,18 @@ static void property_release_alias(Object *obj, const char *name, void *opaque)
if (!(prop->flags & OBJ_PROP_ALIAS_CLASS)) {
g_free(prop->target_name);
g_free(prop);
+ } else {
+ Object **target_obj = object_alias_get_targetp(obj, prop);
+
+ if (*target_obj) {
+ ObjectProperty *target_prop = object_property_find_err(*target_obj,
+ prop->target_name,
+ &error_abort);
+ if (*target_obj != obj &&
+ !object_property_is_child(target_prop)) {
+ object_unref(*target_obj);
+ }
+ }
}
}
@@ -3202,6 +3214,35 @@ object_class_property_add_alias(ObjectClass *klass, const char *name,
return op;
}
+void object_property_set_alias(Object *obj, const char *name,
+ Object *target_obj)
+{
+ AliasProperty *prop;
+ ObjectProperty *op, *target_prop;
+ Object **target_objp;
+
+ op = object_property_find_err(obj, name, &error_abort);
+ prop = op->opaque;
+ assert(prop->flags & OBJ_PROP_ALIAS_CLASS);
+
+ target_objp = object_alias_get_targetp(obj, prop);
+ if (*target_objp) {
+ target_prop = object_property_find_err(*target_objp, prop->target_name,
+ &error_abort);
+ if (*target_objp != obj && !object_property_is_child(target_prop)) {
+ object_unref(*target_objp);
+ }
+ }
+ *target_objp = target_obj;
+ if (*target_objp) {
+ target_prop = object_property_find_err(*target_objp, prop->target_name,
+ &error_abort);
+ if (*target_objp != obj && !object_property_is_child(target_prop)) {
+ object_ref(*target_objp);
+ }
+ }
+}
+
void object_property_set_description(Object *obj, const char *name,
const char *description)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v3 4/8] hw/i386/pc.c: convert pcspk-audiodev object prop to a class prop
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
` (2 preceding siblings ...)
2026-09-02 14:40 ` [PATCH v3 3/8] qom/object.c: introduce object_property_set_alias() function Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 21:08 ` Philippe Mathieu-Daudé
2026-09-02 14:40 ` [PATCH v3 5/8] hw/i386/pc.c: convert rtc-time " Mark Cave-Ayland
` (3 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
---
include/hw/i386/pc.h | 2 ++
hw/i386/pc.c | 9 ++++++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index ac03da97b6..bd800e7ff0 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -38,6 +38,8 @@ typedef struct PCMachineState {
DeviceState *iommu;
BusState *idebus[MAX_IDE_BUS];
+ Object *alias_pcspk;
+
/* Configuration options: */
uint64_t max_ram_below_4g;
OnOffAuto vmport;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index e9e4fc262b..5293c59d66 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1643,8 +1643,8 @@ static void pc_machine_initfn(Object *obj)
pc_system_flash_create(pcms);
pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
- object_property_add_alias(OBJECT(pcms), "pcspk-audiodev",
- OBJECT(pcms->pcspk), "audiodev");
+ object_property_set_alias(OBJECT(pcms), "pcspk-audiodev",
+ OBJECT(pcms->pcspk));
if (pcmc->pci_enabled) {
cxl_machine_init(obj, &pcms->cxl_devices_state);
}
@@ -1788,7 +1788,10 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
"Set IGVM configuration");
#endif
-
+ object_class_property_add_alias(oc, "pcspk-audiodev",
+ offsetof(PCMachineState, alias_pcspk),
+ TYPE_PC_SPEAKER,
+ "audiodev");
}
static const TypeInfo pc_machine_info = {
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v3 4/8] hw/i386/pc.c: convert pcspk-audiodev object prop to a class prop
2026-09-02 14:40 ` [PATCH v3 4/8] hw/i386/pc.c: convert pcspk-audiodev object prop to a class prop Mark Cave-Ayland
@ 2026-09-02 21:08 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 21:08 UTC (permalink / raw)
To: Mark Cave-Ayland, pbonzini, richard.henderson, mst, mtosatti,
marcandre.lureau, armbru, qemu-devel
On 2/9/26 16:40, Mark Cave-Ayland wrote:
> Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
> ---
> include/hw/i386/pc.h | 2 ++
> hw/i386/pc.c | 9 ++++++---
> 2 files changed, 8 insertions(+), 3 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 5/8] hw/i386/pc.c: convert rtc-time object prop to a class prop
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
` (3 preceding siblings ...)
2026-09-02 14:40 ` [PATCH v3 4/8] hw/i386/pc.c: convert pcspk-audiodev object prop to a class prop Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 6/8] hw/i386/pc.c: convert PC_MACHINE_ACPI_DEVICE_PROP from object prop to " Mark Cave-Ayland
` (2 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/hw/i386/pc.h | 1 +
hw/i386/pc.c | 7 +++++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index bd800e7ff0..0b925ccd8f 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -39,6 +39,7 @@ typedef struct PCMachineState {
BusState *idebus[MAX_IDE_BUS];
Object *alias_pcspk;
+ Object *alias_rtc_time;
/* Configuration options: */
uint64_t max_ram_below_4g;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 5293c59d66..f8969ddebc 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1097,8 +1097,7 @@ void pc_basic_device_init(struct PCMachineState *pcms,
qdev_connect_gpio_out(DEVICE(rtc_state), 0, rtc_irq);
}
- object_property_add_alias(OBJECT(pcms), "rtc-time", OBJECT(rtc_state),
- "date");
+ object_property_set_alias(OBJECT(pcms), "rtc-time", OBJECT(rtc_state));
#ifdef CONFIG_XEN_EMU
if (xen_mode == XEN_EMULATE) {
@@ -1792,6 +1791,10 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
offsetof(PCMachineState, alias_pcspk),
TYPE_PC_SPEAKER,
"audiodev");
+ object_class_property_add_alias(oc, "rtc-time",
+ offsetof(PCMachineState, alias_rtc_time),
+ TYPE_MC146818_RTC,
+ "date");
}
static const TypeInfo pc_machine_info = {
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v3 6/8] hw/i386/pc.c: convert PC_MACHINE_ACPI_DEVICE_PROP from object prop to class prop
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
` (4 preceding siblings ...)
2026-09-02 14:40 ` [PATCH v3 5/8] hw/i386/pc.c: convert rtc-time " Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 7/8] hw/i386/pc_sysfw.c: convert pflash0 and pflash1 object props to class props Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 8/8] hw/i386/sgx-epc.c: convert SGX_EPC_SIZE_PROP object prop to class prop Mark Cave-Ayland
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/i386/pc.c | 5 +++++
hw/i386/pc_piix.c | 5 -----
hw/i386/pc_q35.c | 5 -----
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f8969ddebc..876ebaadb8 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1795,6 +1795,11 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
offsetof(PCMachineState, alias_rtc_time),
TYPE_MC146818_RTC,
"date");
+ object_class_property_add_link(oc, PC_MACHINE_ACPI_DEVICE_PROP,
+ TYPE_HOTPLUG_HANDLER,
+ offsetof(X86MachineState, acpi_dev),
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
}
static const TypeInfo pc_machine_info = {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index a929cc4dec..63c4667ea3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -306,11 +306,6 @@ static void pc_init1(MachineState *machine, const char *pci_type)
/* TODO: Populate SPD eeprom data. */
smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
- object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
- TYPE_HOTPLUG_HANDLER,
- (Object **)&x86ms->acpi_dev,
- object_property_allow_set_link,
- OBJ_PROP_LINK_STRONG);
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
piix4_pm, &error_abort);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 94cd71124b..c3ce9c5649 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -247,11 +247,6 @@ static void pc_q35_init(MachineState *machine)
x86ms->rtc = ISA_DEVICE(object_resolve_path_component(OBJECT(lpc), "rtc"));
- object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
- TYPE_HOTPLUG_HANDLER,
- (Object **)&x86ms->acpi_dev,
- object_property_allow_set_link,
- OBJ_PROP_LINK_STRONG);
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
OBJECT(lpc), &error_abort);
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v3 7/8] hw/i386/pc_sysfw.c: convert pflash0 and pflash1 object props to class props
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
` (5 preceding siblings ...)
2026-09-02 14:40 ` [PATCH v3 6/8] hw/i386/pc.c: convert PC_MACHINE_ACPI_DEVICE_PROP from object prop to " Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
2026-09-02 14:40 ` [PATCH v3 8/8] hw/i386/sgx-epc.c: convert SGX_EPC_SIZE_PROP object prop to class prop Mark Cave-Ayland
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
Now that the pflash0 and pflash1 machine properties are class properties, if
they are unspecified then QOM returns an empty string as opposed to returning
a property not found error.
Before this patch:
$ ./build/qemu-system-x86_64 -M q35 -monitor stdio
QEMU 11.1.50 monitor - type 'help' for more information
(qemu) qom-get /machine pflash0
Error: Property 'pc-q35-11.1-machine.pflash0' not found
After this patch:
$ ./build/qemu-system-x86_64 -M q35 -monitor stdio
QEMU 11.1.50 monitor - type 'help' for more information
(qemu) qom-get /machine pflash0
""
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/hw/i386/pc.h | 2 ++
hw/i386/pc.c | 8 ++++++++
hw/i386/pc_sysfw.c | 7 +------
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 0b925ccd8f..8369263691 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -40,6 +40,8 @@ typedef struct PCMachineState {
Object *alias_pcspk;
Object *alias_rtc_time;
+ Object *alias_pflash0;
+ Object *alias_pflash1;
/* Configuration options: */
uint64_t max_ram_below_4g;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 876ebaadb8..ddb75a2ec0 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1800,6 +1800,14 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
offsetof(X86MachineState, acpi_dev),
object_property_allow_set_link,
OBJ_PROP_LINK_STRONG);
+ object_class_property_add_alias(oc, "pflash0",
+ offsetof(PCMachineState, alias_pflash0),
+ TYPE_PFLASH_CFI01,
+ "drive");
+ object_class_property_add_alias(oc, "pflash1",
+ offsetof(PCMachineState, alias_pflash1),
+ TYPE_PFLASH_CFI01,
+ "drive");
}
static const TypeInfo pc_machine_info = {
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 1a41a5972b..441e777191 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -85,8 +85,7 @@ static PFlashCFI01 *pc_pflash_create(PCMachineState *pcms,
qdev_prop_set_uint8(dev, "width", 1);
qdev_prop_set_string(dev, "name", name);
object_property_add_child(OBJECT(pcms), name, OBJECT(dev));
- object_property_add_alias(OBJECT(pcms), alias_prop_name,
- OBJECT(dev), "drive");
+ object_property_set_alias(OBJECT(pcms), alias_prop_name, OBJECT(dev));
/*
* The returned reference is tied to the child property and
* will be removed with object_unparent.
@@ -109,16 +108,12 @@ void pc_system_flash_create(PCMachineState *pcms)
void pc_system_flash_cleanup_unused(PCMachineState *pcms)
{
- char *prop_name;
int i;
assert(PC_MACHINE_GET_CLASS(pcms)->pci_enabled);
for (i = 0; i < ARRAY_SIZE(pcms->flash); i++) {
if (!qdev_is_realized(DEVICE(pcms->flash[i]))) {
- prop_name = g_strdup_printf("pflash%d", i);
- object_property_del(OBJECT(pcms), prop_name);
- g_free(prop_name);
object_unparent(OBJECT(pcms->flash[i]));
pcms->flash[i] = NULL;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v3 8/8] hw/i386/sgx-epc.c: convert SGX_EPC_SIZE_PROP object prop to class prop
2026-09-02 14:40 [PATCH v3 0/8] hw/i386: convert object props to class props Mark Cave-Ayland
` (6 preceding siblings ...)
2026-09-02 14:40 ` [PATCH v3 7/8] hw/i386/pc_sysfw.c: convert pflash0 and pflash1 object props to class props Mark Cave-Ayland
@ 2026-09-02 14:40 ` Mark Cave-Ayland
7 siblings, 0 replies; 15+ messages in thread
From: Mark Cave-Ayland @ 2026-09-02 14:40 UTC (permalink / raw)
To: pbonzini, richard.henderson, mst, mtosatti, marcandre.lureau,
armbru, qemu-devel
Remove sgx_epc_init() since it is no longer required.
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
hw/i386/sgx-epc.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index d3fe10028c..29cda843c9 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -41,12 +41,6 @@ static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, &value, errp);
}
-static void sgx_epc_init(Object *obj)
-{
- object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size,
- NULL, NULL, NULL);
-}
-
static void sgx_epc_realize(DeviceState *dev, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
@@ -164,13 +158,17 @@ static void sgx_epc_class_init(ObjectClass *oc, const void *data)
mdc->get_plugged_size = sgx_epc_md_get_plugged_size;
mdc->get_memory_region = sgx_epc_md_get_memory_region;
mdc->fill_device_info = sgx_epc_md_fill_device_info;
+
+ object_class_property_add(oc, SGX_EPC_SIZE_PROP, "uint64",
+ sgx_epc_get_size,
+ NULL,
+ NULL, NULL);
}
static const TypeInfo sgx_epc_info = {
.name = TYPE_SGX_EPC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SGXEPCDevice),
- .instance_init = sgx_epc_init,
.class_init = sgx_epc_class_init,
.class_size = sizeof(DeviceClass),
.interfaces = (const InterfaceInfo[]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread