From db57fef1e285a1f56a2d99b83456abf2f0b86e96 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 29 Jun 2020 21:34:22 +0200 Subject: [PATCH] qom: Introduce object_property_try_add_child() object_property_add() does not allow object_property_try_add() to gracefully fail as &error_abort is passed as an error handle. However such failure can easily be triggered from the QMP shell when, for instance, one attempts to create an object with an id that already exists. This is achieved from the following call path: qmp_object_add -> user_creatable_add_dict -> user_creatable_add_type -> object_property_add_child -> object_property_add For instance, from the qmp-shell, call twice: object-add qom-type=memory-backend-ram id=mem1 props.size=1073741824 and QEMU aborts. This behavior is undesired as a user/management application mistake in reusing a property ID shouldn't result in loss of the VM and live data within. This patch introduces a new function, object_property_try_add_child() which takes an error handle and turn object_property_try_add() into a non-static one. Now the call path becomes: user_creatable_add_type -> object_property_try_add_child -> object_property_try_add and the error is returned gracefully to the QMP client. (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"return": {}} (QEMU) object-add qom-type=memory-backend-ram id=mem2 props.size=4294967296 {"error": {"class": "GenericError", "desc": "attempt to add duplicate property 'mem2' to object (type 'container')"}} Signed-off-by: Eric Auger Fixes: d2623129a7de ("qom: Drop parameter @errp of object_property_add() & friends") Reviewed-by: Markus Armbruster Reviewed-by: Greg Kurz Tested-by: Greg Kurz Message-Id: <20200629193424.30280-2-eric.auger@redhat.com> Signed-off-by: Paolo Bonzini --- include/qom/object.h | 26 ++++++++++++++++++++++++-- qom/object.c | 21 ++++++++++++++++----- qom/object_interfaces.c | 7 +++++-- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 10fd4a2d4c..79c8f838b6 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1047,7 +1047,7 @@ Object *object_ref(Object *obj); void object_unref(Object *obj); /** - * object_property_add: + * object_property_try_add: * @obj: the object to add a property to * @name: the name of the property. This can contain any character except for * a forward slash. In general, you should use hyphens '-' instead of @@ -1064,10 +1064,23 @@ void object_unref(Object *obj); * meant to allow a property to free its opaque upon object * destruction. This may be NULL. * @opaque: an opaque pointer to pass to the callbacks for the property + * @errp: pointer to error object * * Returns: The #ObjectProperty; this can be used to set the @resolve * callback for child and link properties. */ +ObjectProperty *object_property_try_add(Object *obj, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); + +/** + * object_property_add: + * Same as object_property_try_add() with @errp hardcoded to + * &error_abort. + */ ObjectProperty *object_property_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, @@ -1518,10 +1531,11 @@ Object *object_resolve_path_type(const char *path, const char *typename, Object *object_resolve_path_component(Object *parent, const char *part); /** - * object_property_add_child: + * object_property_try_add_child: * @obj: the object to add a property to * @name: the name of the property * @child: the child object + * @errp: pointer to error object * * Child properties form the composition tree. All objects need to be a child * of another object. Objects can only be a child of one object. @@ -1535,6 +1549,14 @@ Object *object_resolve_path_component(Object *parent, const char *part); * * Returns: The newly added property on success, or %NULL on failure. */ +ObjectProperty *object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp); + +/** + * object_property_add_child: + * Same as object_property_try_add_child() with @errp hardcoded to + * &error_abort + */ ObjectProperty *object_property_add_child(Object *obj, const char *name, Object *child); diff --git a/qom/object.c b/qom/object.c index 4c91de8183..76f5f75239 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1146,7 +1146,7 @@ void object_unref(Object *obj) } } -static ObjectProperty * +ObjectProperty * object_property_try_add(Object *obj, const char *name, const char *type, ObjectPropertyAccessor *get, ObjectPropertyAccessor *set, @@ -1675,8 +1675,8 @@ static void object_finalize_child_property(Object *obj, const char *name, } ObjectProperty * -object_property_add_child(Object *obj, const char *name, - Object *child) +object_property_try_add_child(Object *obj, const char *name, + Object *child, Error **errp) { g_autofree char *type = NULL; ObjectProperty *op; @@ -1685,14 +1685,25 @@ object_property_add_child(Object *obj, const char *name, type = g_strdup_printf("child<%s>", object_get_typename(child)); - op = object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child); + op = object_property_try_add(obj, name, type, object_get_child_property, + NULL, object_finalize_child_property, + child, errp); + if (!op) { + return NULL; + } op->resolve = object_resolve_child_property; object_ref(child); child->parent = obj; return op; } +ObjectProperty * +object_property_add_child(Object *obj, const char *name, + Object *child) +{ + return object_property_try_add_child(obj, name, child, &error_abort); +} + void object_property_allow_set_link(const Object *obj, const char *name, Object *val, Error **errp) { diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c index 15fff66c3c..e8e1523960 100644 --- a/qom/object_interfaces.c +++ b/qom/object_interfaces.c @@ -83,8 +83,11 @@ Object *user_creatable_add_type(const char *type, const char *id, } if (id != NULL) { - object_property_add_child(object_get_objects_root(), - id, obj); + object_property_try_add_child(object_get_objects_root(), + id, obj, &local_err); + if (local_err) { + goto out; + } } if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {