Add a helper object_new_allowed(), use it to track all the places in QEMU
where a new (and especially, random) object can be created.
Currently, it is some form of a cleanup, just to put together all the
errors where QEMU wants to avoid instantiations of abstract classes. The
follow up patch will add more restriction on what object we can create.
A side effect of the cleanup: we could have reported the error message in
different ways even if the reason is always the same (attempts to create an
instance for an abstract class). Now we always report the same message,
could be different from before, but hopefully still worthwhile to change.
Signed-off-by: Peter Xu <peterx@redhat.com>
---
include/qom/object.h | 13 +++++++++++++
chardev/char.c | 4 +---
hw/core/cpu-common.c | 13 +++++++++----
qom/object.c | 17 +++++++++++++++--
qom/object_interfaces.c | 3 +--
system/qdev-monitor.c | 4 +---
6 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/include/qom/object.h b/include/qom/object.h
index 2af9854675..32f1af2986 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -627,6 +627,19 @@ Object *object_new_with_class(ObjectClass *klass);
*/
Object *object_new(const char *typename);
+/**
+ * object_new_allowed:
+ * @klass: The class to instantiate, or fetch instance from.
+ * @errp: The pointer to an Error* that might be filled
+ *
+ * This function detects whether creating a new object of specificed class
+ * is allowed. For example, we do not allow initiations of abstract class.
+ *
+ * Returns: True if new objects allowed, false otherwise. When false is
+ * returned, errp will be set with a proper error message.
+ */
+bool object_new_allowed(ObjectClass *klass, Error **errp);
+
/**
* object_new_with_props:
* @typename: The name of the type of the object to instantiate.
diff --git a/chardev/char.c b/chardev/char.c
index a1722aa076..7fa5b82585 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -533,9 +533,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
return NULL;
}
- if (object_class_is_abstract(oc)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
- "a non-abstract device type");
+ if (!object_new_allowed(oc, errp)) {
return NULL;
}
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 09c7903594..1815b08ba0 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -154,12 +154,17 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
assert(cc->class_by_name);
assert(cpu_model);
oc = cc->class_by_name(cpu_model);
- if (object_class_dynamic_cast(oc, typename) &&
- !object_class_is_abstract(oc)) {
- return oc;
+
+ if (!object_class_dynamic_cast(oc, typename)) {
+ return NULL;
}
- return NULL;
+ /* TODO: allow error message to be passed to the callers */
+ if (!object_new_allowed(oc, NULL)) {
+ return NULL;
+ }
+
+ return oc;
}
static void cpu_common_parse_features(const char *typename, char *features,
diff --git a/qom/object.c b/qom/object.c
index 11424cf471..4f3739fd85 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -797,6 +797,19 @@ Object *object_new(const char *typename)
return object_new_with_type(ti);
}
+bool object_new_allowed(ObjectClass *klass, Error **errp)
+{
+ ERRP_GUARD();
+
+ /* Abstract classes are not instantiable */
+ if (object_class_is_abstract(klass)) {
+ error_setg(errp, "Object type '%s' is abstract",
+ klass->type->name);
+ return false;
+ }
+
+ return true;
+}
Object *object_new_with_props(const char *typename,
Object *parent,
@@ -831,10 +844,10 @@ Object *object_new_with_propv(const char *typename,
return NULL;
}
- if (object_class_is_abstract(klass)) {
- error_setg(errp, "object type '%s' is abstract", typename);
+ if (!object_new_allowed(klass, errp)) {
return NULL;
}
+
obj = object_new_with_type(klass->type);
if (!object_set_propv(obj, errp, vargs)) {
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index e0833c8bfe..d68faf2234 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -102,8 +102,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
return NULL;
}
- if (object_class_is_abstract(klass)) {
- error_setg(errp, "object type '%s' is abstract", type);
+ if (!object_new_allowed(klass, errp)) {
return NULL;
}
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 44994ea0e1..5609e73635 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -255,9 +255,7 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
return NULL;
}
- if (object_class_is_abstract(oc)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
- "a non-abstract device type");
+ if (!object_new_allowed(oc, errp)) {
return NULL;
}
--
2.45.0