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 <[email protected]> --- include/qom/object.h | 11 +++++ qom/object.c | 106 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 12 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 11f55613fc..659b70651a 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -2024,6 +2024,11 @@ ObjectProperty *object_class_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 @@ -2044,6 +2049,12 @@ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, ObjectProperty *object_property_add_alias(Object *obj, const char *name, Object *target_obj, const char *target_name); +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 da4db3e0c7..a1b0ea19a0 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" @@ -2902,14 +2903,22 @@ object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, } 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, @@ -2917,10 +2926,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, @@ -2928,10 +2945,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, @@ -2940,15 +2965,27 @@ 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); + } else { + Object **target_obj = object_alias_get_targetp(obj, prop); + + if (*target_obj) { + object_unref(*target_obj); + } + } } ObjectProperty * @@ -2973,6 +3010,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, @@ -2989,6 +3027,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
