Commit 4f429b2b00 for qemu.org
commit 4f429b2b003dbce29f95268408a929ab52363944
Author: Mark Cave-Ayland <mark.caveayland@nutanix.com>
Date: Mon Sep 21 12:35:09 2026 +0100
qom/object.c: introduce object_class_property_add_alias()
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() function to use the null visitor if the alias target has
not been set, property_set_alias() to return an error, 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>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20260921113559.1299740-4-mark.caveayland@nutanix.com>
diff --git a/include/qom/object.h b/include/qom/object.h
index 3285218664..73d72619b8 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -2279,6 +2279,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
@@ -2299,6 +2304,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 eb5f74fc74..e4e8dc6886 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -35,6 +35,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"
@@ -3052,14 +3053,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,
@@ -3067,10 +3076,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,
@@ -3078,10 +3095,15 @@ 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 {
+ error_setg(errp, "unable to resolve alias property target");
+ }
}
static Object *property_resolve_alias(Object *obj, void *opaque,
@@ -3090,15 +3112,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 *
@@ -3123,6 +3151,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,
@@ -3139,6 +3168,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)
{