Hi

On Wed, Sep 2, 2026 at 6:42 PM Mark Cave-Ayland
<[email protected]> 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 <[email protected]>
> ---
>  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
>


Reply via email to