* [GIT PULL v2 01/23] hw/pci: handle missing bus in prop_pci_busnr_get
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 02/23] chardev/char-socket: handle NULL addr in char_socket_get_addr Marc-André Lureau
` (22 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
When called on an unrealized device (e.g. from
qmp_qom_list_properties), pci_get_bus() returns NULL since the device
has no parent bus. Check for this to avoid a NULL dereference in
pci_bus_num().
Fixes: df9ac7254fd9 ("hw/pci: Add a busnr property to pci_props and use for acpi/gi")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/pci/pci.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4298adf5a0a..cec065d108f 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -64,10 +64,17 @@ static void pcibus_reset_hold(Object *obj, ResetType type);
static bool pcie_has_upstream_port(PCIDevice *dev);
static void prop_pci_busnr_get(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+ void *opaque, Error **errp)
{
- uint8_t busnr = pci_dev_bus_num(PCI_DEVICE(obj));
+ PCIDevice *dev = PCI_DEVICE(obj);
+ PCIBus *bus = pci_get_bus(dev);
+ uint8_t busnr;
+ if (!bus) {
+ error_setg(errp, "device not attached to a PCI bus");
+ return;
+ }
+ busnr = pci_bus_num(bus);
visit_type_uint8(v, name, &busnr, errp);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 02/23] chardev/char-socket: handle NULL addr in char_socket_get_addr
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 01/23] hw/pci: handle missing bus in prop_pci_busnr_get Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 03/23] hw/pci-bridge: handle missing parent in prop_pxb_uid_get Marc-André Lureau
` (21 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
When called on an unrealized chardev (e.g. from
qmp_qom_list_properties), s->addr is NULL. Return an error instead of
assert().
Fixes: 123676e9894f ("char-socket: add 'addr' property")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
chardev/char-socket.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index e064b105c50..b629575fcf8 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1529,6 +1529,10 @@ char_socket_get_addr(Object *obj, Visitor *v, const char *name,
{
SocketChardev *s = SOCKET_CHARDEV(obj);
+ if (!s->addr) {
+ error_setg(errp, "socket not connected");
+ return;
+ }
visit_type_SocketAddress(v, name, &s->addr, errp);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 03/23] hw/pci-bridge: handle missing parent in prop_pxb_uid_get
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 01/23] hw/pci: handle missing bus in prop_pci_busnr_get Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 02/23] chardev/char-socket: handle NULL addr in char_socket_get_addr Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 04/23] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters Marc-André Lureau
` (20 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
When called on an unrealized pxb bus (e.g. from
qmp_qom_list_properties), bus->parent_dev is NULL. The pxb_bus_num()
callback dereferences it unconditionally. Check for this to avoid a
NULL dereference.
Fixes: 97b9cb066e5f ("hw/pci-bridge: Add acpi_uid property to TYPE_PXB_BUS")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/pci-bridge/pci_expander_bridge.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 11623a5666f..40ffbc4e082 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -85,8 +85,14 @@ static uint16_t pxb_bus_numa_node(PCIBus *bus)
static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- uint32_t uid = pci_bus_num(PCI_BUS(obj));
+ PCIBus *bus = PCI_BUS(obj);
+ uint32_t uid;
+ if (!bus->parent_dev) {
+ error_setg(errp, "bus not attached to a device");
+ return;
+ }
+ uid = pci_bus_num(bus);
visit_type_uint32(v, name, &uid, errp);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 04/23] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (2 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 03/23] hw/pci-bridge: handle missing parent in prop_pxb_uid_get Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 05/23] hw/pci-host/q35: " Marc-André Lureau
` (19 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
When called on an unrealized i440FX host bridge (e.g. from
qmp_qom_list_properties), h->bus is NULL since the root bus is only
created during realize. Guard against this in both
pci_hole64_start and pci_hole64_end getters, reporting an error.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
hw/pci-host/i440fx.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c
index e7d638b296c..c1982f7962a 100644
--- a/hw/pci-host/i440fx.c
+++ b/hw/pci-host/i440fx.c
@@ -189,8 +189,14 @@ static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v,
const char *name,
void *opaque, Error **errp)
{
- uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
+ PCIHostState *h = PCI_HOST_BRIDGE(obj);
+ uint64_t hole64_start;
+ if (!h->bus) {
+ error_setg(errp, "PCI host bridge not realized");
+ return;
+ }
+ hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
visit_type_uint64(v, name, &hole64_start, errp);
}
@@ -206,10 +212,15 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
- uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
+ uint64_t hole64_start;
Range w64;
uint64_t value, hole64_end;
+ if (!h->bus) {
+ error_setg(errp, "PCI host bridge not realized");
+ return;
+ }
+ hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
pci_bus_get_w64_range(h->bus, &w64);
value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1;
hole64_end = ROUND_UP(hole64_start + s->pci_hole64_size, 1ULL << 30);
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 05/23] hw/pci-host/q35: handle NULL bus in pci-hole64 getters
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (3 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 04/23] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 06/23] hw/ipmi: reject NULL 'bmc' property rather than crash Marc-André Lureau
` (18 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
When called on an unrealized Q35 host bridge (e.g. from
qmp_qom_list_properties), h->bus is NULL since the root bus is only
created during realize. Guard against this in both the
pci_hole64_start and pci_hole64_end getters.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/pci-host/q35.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index e85e4227b37..355e81bfa20 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -132,8 +132,14 @@ static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- uint64_t hole64_start = q35_host_get_pci_hole64_start_value(obj);
+ PCIHostState *h = PCI_HOST_BRIDGE(obj);
+ uint64_t hole64_start;
+ if (!h->bus) {
+ error_setg(errp, "PCI host bridge not realized");
+ return;
+ }
+ hole64_start = q35_host_get_pci_hole64_start_value(obj);
visit_type_uint64(v, name, &hole64_start, errp);
}
@@ -149,10 +155,15 @@ static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
{
PCIHostState *h = PCI_HOST_BRIDGE(obj);
Q35PCIHost *s = Q35_HOST_DEVICE(obj);
- uint64_t hole64_start = q35_host_get_pci_hole64_start_value(obj);
+ uint64_t hole64_start;
Range w64;
uint64_t value, hole64_end;
+ if (!h->bus) {
+ error_setg(errp, "PCI host bridge not realized");
+ return;
+ }
+ hole64_start = q35_host_get_pci_hole64_start_value(obj);
pci_bus_get_w64_range(h->bus, &w64);
value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1;
hole64_end = ROUND_UP(hole64_start + s->mch.pci_hole64_size, 1ULL << 30);
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 06/23] hw/ipmi: reject NULL 'bmc' property rather than crash
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (4 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 05/23] hw/pci-host/q35: " Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 07/23] hw/xlnx_dp: reject NULL 'dpdma' " Marc-André Lureau
` (17 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/ipmi/ipmi.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
index b49affaccec..74818ff3cea 100644
--- a/hw/ipmi/ipmi.c
+++ b/hw/ipmi/ipmi.c
@@ -97,8 +97,14 @@ static void isa_ipmi_bmc_check(const Object *obj, const char *name,
{
IPMIBmc *bmc = IPMI_BMC(val);
- if (bmc->intf)
+ if (!bmc) {
+ error_setg(errp, "%s cannot be set to NULL", name);
+ return;
+ }
+
+ if (bmc->intf) {
error_setg(errp, "BMC object is already in use");
+ }
}
void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 07/23] hw/xlnx_dp: reject NULL 'dpdma' property rather than crash
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (5 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 06/23] hw/ipmi: reject NULL 'bmc' property rather than crash Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 08/23] hw/intc/apic: move checks to realize() Marc-André Lureau
` (16 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/display/xlnx_dp.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 2486d9e5825..98126ef320d 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -570,6 +570,12 @@ static void xlnx_dp_set_dpdma(const Object *obj, const char *name, Object *val,
Error **errp)
{
XlnxDPState *s = XLNX_DP(obj);
+
+ if (!s) {
+ error_setg(errp, "%s cannot be set to NULL", name);
+ return;
+ }
+
if (s->console) {
DisplaySurface *surface = qemu_console_surface(s->console);
XlnxDPDMAState *dma = XLNX_DPDMA(val);
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 08/23] hw/intc/apic: move checks to realize()
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (6 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 07/23] hw/xlnx_dp: reject NULL 'dpdma' " Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 09/23] backends/cryptodev-lkcf: skip cleanup when not initialized Marc-André Lureau
` (15 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
apic_common_set_id() dereferences s->cpu to check for x2APIC support
when the APIC ID is >= 255. On a standalone APIC object that has not
been attached to a CPU, s->cpu is NULL, causing a segfault.
To solve this, move validation during realize().
Fixes: b5ee0468e9d2 ("apic: add support for x2APIC mode")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/intc/apic_common.c | 23 +++++++++++++----------
target/i386/cpu-apic.c | 6 +-----
2 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index bf4abc21d7b..49c03a5bcee 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -257,6 +257,19 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
static DeviceState *vapic;
uint32_t instance_id = s->initial_apic_id;
+ if (!s->cpu) {
+ error_setg(errp, "APIC is not attached to a CPU");
+ return;
+ }
+
+ if (s->initial_apic_id >= 255 &&
+ !cpu_has_x2apic_feature(&s->cpu->env)) {
+ error_setg(errp, "APIC ID %d requires x2APIC feature in CPU",
+ s->initial_apic_id);
+ error_append_hint(errp, "Try x2apic=on in -cpu.\n");
+ return;
+ }
+
/* Normally initial APIC ID should be no more than hundreds */
assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
@@ -410,7 +423,6 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
APICCommonState *s = APIC_COMMON(obj);
DeviceState *dev = DEVICE(obj);
uint32_t value;
- Error *local_err = NULL;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
@@ -421,15 +433,6 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
return;
}
- if (value >= 255 && !cpu_has_x2apic_feature(&s->cpu->env)) {
- error_setg(&local_err,
- "APIC ID %d requires x2APIC feature in CPU",
- value);
- error_append_hint(&local_err, "Try x2apic=on in -cpu.\n");
- error_propagate(errp, local_err);
- return;
- }
-
s->initial_apic_id = value;
s->id = (uint8_t)value;
}
diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c
index 5599a4675c5..04b7257ad12 100644
--- a/target/i386/cpu-apic.c
+++ b/target/i386/cpu-apic.c
@@ -56,11 +56,7 @@ void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
cpu->apic_state->cpu = cpu;
cpu->apic_state->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
- /*
- * apic_common_set_id needs to check if the CPU has x2APIC
- * feature in case APIC ID >= 255, so we need to set cpu->apic_state->cpu
- * before setting APIC ID
- */
+ /* cpu must be set before realize, which validates the APIC ID */
qdev_prop_set_uint32(DEVICE(cpu->apic_state), "id", cpu->apic_id);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 09/23] backends/cryptodev-lkcf: skip cleanup when not initialized
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (7 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 08/23] hw/intc/apic: move checks to realize() Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 10/23] system/ioport: minor code simplification Marc-André Lureau
` (14 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
cryptodev_lkcf_cleanup() locks a mutex that is only initialized
during the init vfunc (called at realize time). When the backend
is destroyed without ever being realized, the mutex is uninitialized
and the lock aborts.
Return early from cleanup when the backend was never started.
Note: it looks like cryptodev init/cleanup callbacks should rather be
regular complete/finalize overrides (calling the parent method).
Fixes: 39fff6f3e8b3 ("cryptodev: Add a lkcf-backend for cryptodev")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
backends/cryptodev-lkcf.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c
index 40c7bd3c5a0..3fe29d3104c 100644
--- a/backends/cryptodev-lkcf.c
+++ b/backends/cryptodev-lkcf.c
@@ -255,6 +255,10 @@ static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp)
CryptoDevBackendClient *cc;
CryptoDevLKCFTask *task, *next;
+ if (!cryptodev_backend_is_ready(backend)) {
+ return;
+ }
+
qemu_mutex_lock(&lkcf->mutex);
lkcf->running = false;
qemu_mutex_unlock(&lkcf->mutex);
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 10/23] system/ioport: minor code simplification
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (8 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 09/23] backends/cryptodev-lkcf: skip cleanup when not initialized Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 11/23] hw/core/machine: free shim_filename on finalization Marc-André Lureau
` (13 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Drop needless memset() and replace g_malloc0() with g_new().
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
system/ioport.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/system/ioport.c b/system/ioport.c
index 1a0e01fd06b..0a1b80f2994 100644
--- a/system/ioport.c
+++ b/system/ioport.c
@@ -230,9 +230,8 @@ static void portio_list_add_1(PortioList *piolist,
mrpio = MEMORY_REGION_PORTIO_LIST(
object_new(TYPE_MEMORY_REGION_PORTIO_LIST));
mrpio->portio_opaque = piolist->opaque;
- mrpio->ports = g_malloc0(sizeof(MemoryRegionPortio) * (count + 1));
+ mrpio->ports = g_new0(MemoryRegionPortio, count + 1);
memcpy(mrpio->ports, pio_init, sizeof(MemoryRegionPortio) * count);
- memset(mrpio->ports + count, 0, sizeof(MemoryRegionPortio));
/* Adjust the offsets to all be zero-based for the region. */
for (i = 0; i < count; ++i) {
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 11/23] hw/core/machine: free shim_filename on finalization
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (9 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 10/23] system/ioport: minor code simplification Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 12/23] net/filter: free old values in property setters Marc-André Lureau
` (12 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
machine_set_shim allocates shim_filename via g_strdup, but
machine_finalize did not free it.
Fixes: a5bd044b1579 ("x86/loader: add -shim option")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/core/machine.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 17970b78b65..4d8b15d99e9 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1286,6 +1286,7 @@ static void machine_finalize(Object *obj)
MachineState *ms = MACHINE(obj);
machine_free_boot_config(ms);
+ g_free(ms->shim_filename);
g_free(ms->kernel_filename);
g_free(ms->initrd_filename);
g_free(ms->kernel_cmdline);
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 12/23] net/filter: free old values in property setters
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (10 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 11/23] hw/core/machine: free shim_filename on finalization Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 13/23] target/i386/sev: add finalize functions and fix leaking setters Marc-André Lureau
` (11 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
netfilter_set_position and netfilter_set_netdev_id overwrote their
respective fields with g_strdup without freeing the previous value,
leaking memory on each property write.
Fixes: fdccce459621 ("init/cleanup of netfilter object")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
net/filter.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/filter.c b/net/filter.c
index c7cc6615dc9..389f3b0bfef 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -130,6 +130,7 @@ static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp)
{
NetFilterState *nf = NETFILTER(obj);
+ g_free(nf->netdev_id);
nf->netdev_id = g_strdup(str);
}
@@ -182,6 +183,7 @@ static void netfilter_set_position(Object *obj, const char *str, Error **errp)
{
NetFilterState *nf = NETFILTER(obj);
+ g_free(nf->position);
nf->position = g_strdup(str);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 13/23] target/i386/sev: add finalize functions and fix leaking setters
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (11 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 12/23] net/filter: free old values in property setters Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 14/23] target/i386/kvm/tdx: free strings in tdx_guest_finalize Marc-André Lureau
` (10 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
None of the three SEV types (sev-common, sev-guest, sev-snp-guest)
had instance_finalize functions, so all string fields allocated
during init or by property setters were leaked on object destruction.
Add sev_common_finalize, sev_guest_finalize, and
sev_snp_guest_finalize to free the allocated fields.
Also fix sev_common_set_sev_device, sev_guest_set_dh_cert_file,
and sev_guest_set_session_file to free the old value before
replacing it.
Fixes: a9b4942f485 ("target/i386: add Secure Encrypted
Virtualization (SEV) object")
Fixes: 7b34df44260 ("i386/sev: Introduce 'sev-snp-guest' object")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
target/i386/sev.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index b44b5a1c2b9..99cf30806be 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -2526,6 +2526,7 @@ sev_common_get_sev_device(Object *obj, Error **errp)
static void
sev_common_set_sev_device(Object *obj, const char *value, Error **errp)
{
+ g_free(SEV_COMMON(obj)->sev_device);
SEV_COMMON(obj)->sev_device = g_strdup(value);
}
@@ -2830,12 +2831,21 @@ sev_common_instance_init(Object *obj)
QTAILQ_INIT(&sev_common->launch_vmsa);
}
+static void
+sev_common_finalize(Object *obj)
+{
+ SevCommonState *sev_common = SEV_COMMON(obj);
+
+ g_free(sev_common->sev_device);
+}
+
/* sev guest info common to sev/sev-es/sev-snp */
static const TypeInfo sev_common_info = {
.parent = TYPE_X86_CONFIDENTIAL_GUEST,
.name = TYPE_SEV_COMMON,
.instance_size = sizeof(SevCommonState),
.instance_init = sev_common_instance_init,
+ .instance_finalize = sev_common_finalize,
.class_size = sizeof(SevCommonStateClass),
.class_init = sev_common_class_init,
.abstract = true,
@@ -2855,6 +2865,7 @@ sev_guest_get_dh_cert_file(Object *obj, Error **errp)
static void
sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
{
+ g_free(SEV_GUEST(obj)->dh_cert_file);
SEV_GUEST(obj)->dh_cert_file = g_strdup(value);
}
@@ -2869,6 +2880,7 @@ sev_guest_get_session_file(Object *obj, Error **errp)
static void
sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
{
+ g_free(SEV_GUEST(obj)->session_file);
SEV_GUEST(obj)->session_file = g_strdup(value);
}
@@ -2936,12 +2948,23 @@ sev_guest_instance_init(Object *obj)
sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
}
+static void
+sev_guest_finalize(Object *obj)
+{
+ SevGuestState *sev_guest = SEV_GUEST(obj);
+
+ g_free(sev_guest->dh_cert_file);
+ g_free(sev_guest->session_file);
+ g_free(sev_guest->measurement);
+}
+
/* guest info specific sev/sev-es */
static const TypeInfo sev_guest_info = {
.parent = TYPE_SEV_COMMON,
.name = TYPE_SEV_GUEST,
.instance_size = sizeof(SevGuestState),
.instance_init = sev_guest_instance_init,
+ .instance_finalize = sev_guest_finalize,
.class_init = sev_guest_class_init,
};
@@ -3194,6 +3217,19 @@ sev_snp_guest_instance_init(Object *obj)
sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
}
+static void
+sev_snp_guest_finalize(Object *obj)
+{
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
+
+ g_free(sev_snp_guest->guest_visible_workarounds);
+ g_free(sev_snp_guest->id_block_base64);
+ g_free(sev_snp_guest->id_block);
+ g_free(sev_snp_guest->id_auth_base64);
+ g_free(sev_snp_guest->id_auth);
+ g_free(sev_snp_guest->host_data);
+}
+
/* guest info specific to sev-snp */
static const TypeInfo sev_snp_guest_info = {
.parent = TYPE_SEV_COMMON,
@@ -3201,6 +3237,7 @@ static const TypeInfo sev_snp_guest_info = {
.instance_size = sizeof(SevSnpGuestState),
.class_init = sev_snp_guest_class_init,
.instance_init = sev_snp_guest_instance_init,
+ .instance_finalize = sev_snp_guest_finalize,
};
static void
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 14/23] target/i386/kvm/tdx: free strings in tdx_guest_finalize
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (12 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 13/23] target/i386/sev: add finalize functions and fix leaking setters Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 15/23] hw/i386/nitro_enclave: add instance finalize Marc-André Lureau
` (9 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
tdx_guest_finalize was empty, so mrconfigid, mrowner, and
mrownerconfig set by property setters were never freed.
Fixes: d05a0858cf87 ("i386/tdx: Support user configurable mrconfigid/mrowner/mrownerconfig")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
target/i386/kvm/tdx.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
index 4714c9d514e..df46fce7693 100644
--- a/target/i386/kvm/tdx.c
+++ b/target/i386/kvm/tdx.c
@@ -1585,6 +1585,11 @@ static void tdx_guest_init(Object *obj)
static void tdx_guest_finalize(Object *obj)
{
+ TdxGuest *tdx = TDX_GUEST(obj);
+
+ g_free(tdx->mrconfigid);
+ g_free(tdx->mrowner);
+ g_free(tdx->mrownerconfig);
}
static ResettableState *tdx_reset_state(Object *obj)
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 15/23] hw/i386/nitro_enclave: add instance finalize
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (13 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 14/23] target/i386/kvm/tdx: free strings in tdx_guest_finalize Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 16/23] hw/i386/pc: free pcspk on finalization Marc-André Lureau
` (8 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Property setter strings (vsock, id, parent_role, parent_id) were
never freed because nitro_enclave_machine_info had no
instance_finalize.
Fixes: f1826463d2e8 ("machine/nitro-enclave: New machine type for AWS Nitro Enclaves")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/i386/nitro_enclave.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/hw/i386/nitro_enclave.c b/hw/i386/nitro_enclave.c
index a29f0044d0e..1ce9ee3358a 100644
--- a/hw/i386/nitro_enclave.c
+++ b/hw/i386/nitro_enclave.c
@@ -337,11 +337,22 @@ static void nitro_enclave_class_init(ObjectClass *oc, const void *data)
"Set parent instance identifier");
}
+static void nitro_enclave_machine_finalize(Object *obj)
+{
+ NitroEnclaveMachineState *nems = NITRO_ENCLAVE_MACHINE(obj);
+
+ g_free(nems->vsock);
+ g_free(nems->id);
+ g_free(nems->parent_role);
+ g_free(nems->parent_id);
+}
+
static const TypeInfo nitro_enclave_machine_info = {
.name = TYPE_NITRO_ENCLAVE_MACHINE,
.parent = TYPE_MICROVM_MACHINE,
.instance_size = sizeof(NitroEnclaveMachineState),
.instance_init = nitro_enclave_machine_initfn,
+ .instance_finalize = nitro_enclave_machine_finalize,
.class_size = sizeof(NitroEnclaveMachineClass),
.class_init = nitro_enclave_class_init,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 16/23] hw/i386/pc: free pcspk on finalization
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (14 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 15/23] hw/i386/nitro_enclave: add instance finalize Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 17/23] hw/tpm: free PPI buffer " Marc-André Lureau
` (7 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Add pc_machine_finalize() to unref the pcspk device when it was never
realized. Once realized, the bus owns it and no action is needed.
Fixes: 6b8d1416482f ("audio: create pcspk device early")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/i386/pc.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2ecad3c503f..7b6ad97e5a9 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1610,6 +1610,15 @@ static void pc_machine_initfn(Object *obj)
}
}
+static void pc_machine_finalize(Object *obj)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+
+ if (pcms->pcspk && !qdev_is_realized(DEVICE(pcms->pcspk))) {
+ object_unref(OBJECT(pcms->pcspk));
+ }
+}
+
static void pc_machine_reset(MachineState *machine, ResetType type)
{
CPUState *cs;
@@ -1748,6 +1757,7 @@ static const TypeInfo pc_machine_info = {
.abstract = true,
.instance_size = sizeof(PCMachineState),
.instance_init = pc_machine_initfn,
+ .instance_finalize = pc_machine_finalize,
.class_size = sizeof(PCMachineClass),
.class_init = pc_machine_class_init,
.interfaces = (const InterfaceInfo[]) {
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 17/23] hw/tpm: free PPI buffer on finalization
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (15 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 16/23] hw/i386/pc: free pcspk on finalization Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 18/23] hw/loongarch/virt: free flash devices and OEM strings " Marc-André Lureau
` (6 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
The PPI buffer is allocated with qemu_memalign() in instance_init but
never freed when the device is destroyed.
Fixes: 46cd2c1050f0 ("hw/tpm: add PPI support to tpm-tis-device for ARM64 virt")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
hw/tpm/tpm_tis_sysbus.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c
index f9cd1c8b5c6..16bb17874b8 100644
--- a/hw/tpm/tpm_tis_sysbus.c
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -148,11 +148,20 @@ static void tpm_tis_sysbus_class_init(ObjectClass *klass, const void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
+static void tpm_tis_sysbus_finalize(Object *obj)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj);
+ TPMState *s = &sbdev->state;
+
+ qemu_vfree(s->ppi.buf);
+}
+
static const TypeInfo tpm_tis_sysbus_info = {
.name = TYPE_TPM_TIS_SYSBUS,
.parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.instance_size = sizeof(TPMStateSysBus),
.instance_init = tpm_tis_sysbus_initfn,
+ .instance_finalize = tpm_tis_sysbus_finalize,
.class_init = tpm_tis_sysbus_class_init,
.interfaces = (const InterfaceInfo[]) {
{ TYPE_TPM_IF },
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 18/23] hw/loongarch/virt: free flash devices and OEM strings on finalization
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (16 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 17/23] hw/tpm: free PPI buffer " Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 19/23] hw/ppc/spapr: free host_model and host_serial " Marc-André Lureau
` (5 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Flash devices created in virt_initfn() via qdev_new() hold an extra
reference that is only dropped on sysbus_realize_and_unref(). When the
machine is destroyed before realization, the flash objects leak. Also,
the oem_id and oem_table_id strings from g_strndup() are never freed.
Fixes: 445c9c645 ("hw/loongarch/virt: Allow user to customize OEM ID and OEM table ID")
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/loongarch/virt.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f68ccdb12b7..6693dea647b 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1566,6 +1566,19 @@ static void virt_class_init(ObjectClass *oc, const void *data)
#define DEFINE_VIRT_MACHINE(major, minor) \
DEFINE_VIRT_MACHINE_VERSION(false, major, minor)
+static void virt_instance_finalize(Object *obj)
+{
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+ for (int i = 0; i < ARRAY_SIZE(lvms->flash); i++) {
+ if (lvms->flash[i] && !qdev_is_realized(DEVICE(lvms->flash[i]))) {
+ object_unref(OBJECT(lvms->flash[i]));
+ }
+ }
+ g_free(lvms->oem_id);
+ g_free(lvms->oem_table_id);
+}
+
static const TypeInfo virt_machine_info = {
.name = TYPE_LOONGARCH_VIRT_MACHINE,
.parent = TYPE_MACHINE,
@@ -1573,6 +1586,7 @@ static const TypeInfo virt_machine_info = {
.instance_size = sizeof(LoongArchVirtMachineState),
.class_init = virt_class_init,
.instance_init = virt_initfn,
+ .instance_finalize = virt_instance_finalize,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 19/23] hw/ppc/spapr: free host_model and host_serial on finalization
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (17 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 18/23] hw/loongarch/virt: free flash devices and OEM strings " Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 20/23] target/riscv: fix general_user_opts hash table leak Marc-André Lureau
` (4 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
The host_model and host_serial strings are allocated via g_strdup in
property setters but never freed when the machine is destroyed.
Fixes: 27461d69a0f ("ppc: add host-serial and host-model machine attributes (CVE-2019-8934)")
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/ppc/spapr.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 191f7431bdf..f0e99bb5be7 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3517,6 +3517,8 @@ static void spapr_machine_finalizefn(Object *obj)
SpaprMachineState *spapr = SPAPR_MACHINE(obj);
g_free(spapr->kvm_type);
+ g_free(spapr->host_model);
+ g_free(spapr->host_serial);
}
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 20/23] target/riscv: fix general_user_opts hash table leak
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (18 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 19/23] hw/ppc/spapr: free host_model and host_serial " Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 21/23] target/riscv: use hash table as set for user_options Marc-André Lureau
` (3 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
The global general_user_opts hash table is recreated on every
riscv_cpu_init() call, leaking the previous one.
Furthermore, the CPU settings should be associated with their instance
and not global.
Add a finalize() to free associated instances.
Fixes: d167a2247ede ("target/riscv: move 'pmu-mask' and 'pmu-num' to riscv_cpu_properties[]")
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
target/riscv/cpu.h | 3 ++-
target/riscv/cpu.c | 53 ++++++++++++++++++++++++++++------------------
target/riscv/kvm/kvm-cpu.c | 8 +++----
3 files changed, 38 insertions(+), 26 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7d79c7a5a7e..f7d8a08c087 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -547,6 +547,7 @@ struct ArchCPU {
uint32_t pmu_avail_ctrs;
/* Mapping of events to counters */
GHashTable *pmu_event_ctr_map;
+ GHashTable *user_options;
const GPtrArray *decoders;
};
@@ -620,7 +621,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
bool probe, uintptr_t retaddr);
char *riscv_isa_string(RISCVCPU *cpu);
int riscv_cpu_max_xlen(RISCVCPUClass *mcc);
-bool riscv_cpu_option_set(const char *optname);
+bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname);
#ifndef CONFIG_USER_ONLY
void riscv_cpu_do_interrupt(CPUState *cpu);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 862834b4809..57000983edd 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -27,6 +27,7 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
+#include "qemu/timer.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/qdev-prop-internal.h"
#include "migration/vmstate.h"
@@ -59,18 +60,16 @@ bool riscv_cpu_is_32bit(RISCVCPU *cpu)
return riscv_cpu_mxl(&cpu->env) == MXL_RV32;
}
-/* Hash that stores general user set numeric options */
-static GHashTable *general_user_opts;
-
-static void cpu_option_add_user_setting(const char *optname, uint32_t value)
+static void cpu_option_add_user_setting(RISCVCPU *cpu, const char *optname,
+ uint32_t value)
{
- g_hash_table_insert(general_user_opts, (gpointer)optname,
+ g_hash_table_insert(cpu->user_options, (gpointer)optname,
GUINT_TO_POINTER(value));
}
-bool riscv_cpu_option_set(const char *optname)
+bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname)
{
- return g_hash_table_contains(general_user_opts, optname);
+ return g_hash_table_contains(cpu->user_options, optname);
}
#ifndef CONFIG_USER_ONLY
@@ -1126,7 +1125,7 @@ static void riscv_cpu_init(Object *obj)
"riscv.cpu.rnmi", RNMI_MAX);
#endif /* CONFIG_USER_ONLY */
- general_user_opts = g_hash_table_new(g_str_hash, g_str_equal);
+ cpu->user_options = g_hash_table_new(g_str_hash, g_str_equal);
/*
* The timer and performance counters extensions were supported
@@ -1291,7 +1290,7 @@ static void prop_pmu_num_set(Object *obj, Visitor *v, const char *name,
warn_report("\"pmu-num\" property is deprecated; use \"pmu-mask\"");
cpu->cfg.pmu_mask = pmu_mask;
- cpu_option_add_user_setting("pmu-mask", pmu_mask);
+ cpu_option_add_user_setting(cpu, "pmu-mask", pmu_mask);
}
static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name,
@@ -1333,7 +1332,7 @@ static void prop_pmu_mask_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.pmu_mask = value;
}
@@ -1365,7 +1364,7 @@ static void prop_mmu_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.mmu = value;
}
@@ -1397,7 +1396,7 @@ static void prop_pmp_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.pmp = value;
}
@@ -1437,7 +1436,7 @@ static void prop_num_pmp_regions_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.pmp_regions = value;
}
@@ -1475,7 +1474,7 @@ static void prop_pmp_granularity_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.pmp_granularity = value;
}
@@ -1548,7 +1547,7 @@ static void prop_priv_spec_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, priv_version);
+ cpu_option_add_user_setting(cpu, name, priv_version);
cpu->env.priv_ver = priv_version;
}
@@ -1582,7 +1581,7 @@ static void prop_vext_spec_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, VEXT_VERSION_1_00_0);
+ cpu_option_add_user_setting(cpu, name, VEXT_VERSION_1_00_0);
cpu->env.vext_ver = VEXT_VERSION_1_00_0;
}
@@ -1625,7 +1624,7 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.vlenb = value >> 3;
}
@@ -1666,7 +1665,7 @@ static void prop_elen_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.elen = value;
}
@@ -1702,7 +1701,7 @@ static void prop_cbom_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.cbom_blocksize = value;
}
@@ -1738,7 +1737,7 @@ static void prop_cbop_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.cbop_blocksize = value;
}
@@ -1774,7 +1773,7 @@ static void prop_cboz_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(name, value);
+ cpu_option_add_user_setting(cpu, name, value);
cpu->cfg.cboz_blocksize = value;
}
@@ -2834,6 +2833,17 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename)
DEFINE_RISCV_CPU(type_name, parent_type_name, \
.profile = &(profile_))
+static void riscv_cpu_instance_finalize(Object *obj)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
+#ifndef CONFIG_USER_ONLY
+ g_clear_pointer(&cpu->pmu_timer, timer_free);
+ g_clear_pointer(&cpu->pmu_event_ctr_map, g_hash_table_destroy);
+#endif
+ g_clear_pointer(&cpu->user_options, g_hash_table_destroy);
+}
+
static const TypeInfo riscv_cpu_type_infos[] = {
{
.name = TYPE_RISCV_CPU,
@@ -2841,6 +2851,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.instance_size = sizeof(RISCVCPU),
.instance_align = __alignof(RISCVCPU),
.instance_init = riscv_cpu_init,
+ .instance_finalize = riscv_cpu_instance_finalize,
.abstract = true,
.class_size = sizeof(RISCVCPUClass),
.class_init = riscv_cpu_common_class_init,
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 17ba38403a3..53d88339c13 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -2034,7 +2034,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
}
if (cpu->cfg.ext_zicbom &&
- riscv_cpu_option_set(kvm_cbom_blocksize.name)) {
+ riscv_cpu_option_set(cpu, kvm_cbom_blocksize.name)) {
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
kvm_cbom_blocksize.kvm_reg_id);
@@ -2053,7 +2053,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
}
if (cpu->cfg.ext_zicboz &&
- riscv_cpu_option_set(kvm_cboz_blocksize.name)) {
+ riscv_cpu_option_set(cpu, kvm_cboz_blocksize.name)) {
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
kvm_cboz_blocksize.kvm_reg_id);
@@ -2072,7 +2072,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
}
if (cpu->cfg.ext_zicbop &&
- riscv_cpu_option_set(kvm_cbop_blocksize.name)) {
+ riscv_cpu_option_set(cpu, kvm_cbop_blocksize.name)) {
reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG,
kvm_cbop_blocksize.kvm_reg_id);
@@ -2091,7 +2091,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
}
/* Users are setting vlen, not vlenb */
- if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) {
+ if (riscv_has_ext(env, RVV) && riscv_cpu_option_set(cpu, "vlen")) {
if (!kvm_v_vlenb.supported) {
error_setg(errp, "Unable to set 'vlenb': register not supported");
return;
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 21/23] target/riscv: use hash table as set for user_options
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (19 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 20/23] target/riscv: fix general_user_opts hash table leak Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 22/23] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data Marc-André Lureau
` (2 subsequent siblings)
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
The values stored in user_options are never retrieved, only key
presence is checked. Use g_hash_table_add() instead of
g_hash_table_insert() and drop the unused value parameter.
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
target/riscv/cpu.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 57000983edd..5903df99548 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -60,11 +60,9 @@ bool riscv_cpu_is_32bit(RISCVCPU *cpu)
return riscv_cpu_mxl(&cpu->env) == MXL_RV32;
}
-static void cpu_option_add_user_setting(RISCVCPU *cpu, const char *optname,
- uint32_t value)
+static void cpu_option_add_user_setting(RISCVCPU *cpu, const char *optname)
{
- g_hash_table_insert(cpu->user_options, (gpointer)optname,
- GUINT_TO_POINTER(value));
+ g_hash_table_add(cpu->user_options, (gpointer)optname);
}
bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname)
@@ -1290,7 +1288,7 @@ static void prop_pmu_num_set(Object *obj, Visitor *v, const char *name,
warn_report("\"pmu-num\" property is deprecated; use \"pmu-mask\"");
cpu->cfg.pmu_mask = pmu_mask;
- cpu_option_add_user_setting(cpu, "pmu-mask", pmu_mask);
+ cpu_option_add_user_setting(cpu, "pmu-mask");
}
static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name,
@@ -1332,7 +1330,7 @@ static void prop_pmu_mask_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.pmu_mask = value;
}
@@ -1364,7 +1362,7 @@ static void prop_mmu_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.mmu = value;
}
@@ -1396,7 +1394,7 @@ static void prop_pmp_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.pmp = value;
}
@@ -1436,7 +1434,7 @@ static void prop_num_pmp_regions_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.pmp_regions = value;
}
@@ -1474,7 +1472,7 @@ static void prop_pmp_granularity_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.pmp_granularity = value;
}
@@ -1547,7 +1545,7 @@ static void prop_priv_spec_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, priv_version);
+ cpu_option_add_user_setting(cpu, name);
cpu->env.priv_ver = priv_version;
}
@@ -1581,7 +1579,7 @@ static void prop_vext_spec_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, VEXT_VERSION_1_00_0);
+ cpu_option_add_user_setting(cpu, name);
cpu->env.vext_ver = VEXT_VERSION_1_00_0;
}
@@ -1624,7 +1622,7 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.vlenb = value >> 3;
}
@@ -1665,7 +1663,7 @@ static void prop_elen_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.elen = value;
}
@@ -1701,7 +1699,7 @@ static void prop_cbom_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.cbom_blocksize = value;
}
@@ -1737,7 +1735,7 @@ static void prop_cbop_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.cbop_blocksize = value;
}
@@ -1773,7 +1771,7 @@ static void prop_cboz_blksize_set(Object *obj, Visitor *v, const char *name,
return;
}
- cpu_option_add_user_setting(cpu, name, value);
+ cpu_option_add_user_setting(cpu, name);
cpu->cfg.cboz_blocksize = value;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 22/23] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (20 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 21/23] target/riscv: use hash table as set for user_options Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 5:15 ` [GIT PULL v2 23/23] qtest: add "qom-tests" command Marc-André Lureau
2026-06-06 22:10 ` [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Stefan Hajnoczi
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
The intermediate result of (Y * 10^-R - b) / m can be negative when
the bias (b) is large and the raw register value is small (e.g. zero
on an uninitialized device). Assigning that negative double to uint32_t
is undefined behavior, caught by UBSan/clang.
Use a double intermediate and clamp negative results to zero (suggested
by Daniel Berrangé)
Fixes: 3746d5c15e70 ("hw/i2c: add support for PMBus")
Reviewed-by: Titus Rwantare <titusr@google.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/i2c/pmbus_device.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
index 853dc4b4342..b1f9843f52e 100644
--- a/hw/i2c/pmbus_device.c
+++ b/hw/i2c/pmbus_device.c
@@ -23,8 +23,10 @@ uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value)
uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value)
{
/* X = (Y * 10^-R - b) / m */
- uint32_t x = (value / pow(10, c.R) - c.b) / c.m;
- return x;
+ double x = (value / pow(10, c.R) - c.b) / c.m;
+ return (x > 0
+ ? (x < G_MAXUINT32 ? (uint32_t)x : G_MAXUINT32)
+ : 0);
}
uint16_t pmbus_data2linear_mode(uint16_t value, int exp)
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [GIT PULL v2 23/23] qtest: add "qom-tests" command
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (21 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 22/23] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data Marc-André Lureau
@ 2026-06-06 5:15 ` Marc-André Lureau
2026-06-06 22:10 ` [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Stefan Hajnoczi
23 siblings, 0 replies; 25+ messages in thread
From: Marc-André Lureau @ 2026-06-06 5:15 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanha
Add a new "qom-tests" to exercise basic object lifecycle. Instantiate
all non-abstract objects, get and set properties and unref.
This should quickly find leaks and other related issues that are
eventually triggerable at run-time with QMP qom commands.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/qtest/libqtest.h | 8 ++++++++
system/qtest.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
tests/qtest/libqtest.c | 6 ++++++
tests/qtest/qom-test.c | 12 ++++++++++++
4 files changed, 72 insertions(+)
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index 950ea2baafa..45217fb8dc0 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -426,6 +426,14 @@ char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
void qtest_module_load(QTestState *s, const char *prefix, const char *libname);
+/**
+ * qtest_qom_tests:
+ * @s: #QTestState instance to operate on.
+ *
+ * Run QOM property get/set round-trip tests on all non-abstract types.
+ */
+void qtest_qom_tests(QTestState *s);
+
/**
* qtest_get_irq:
* @s: #QTestState instance to operate on.
diff --git a/system/qtest.c b/system/qtest.c
index d6db057b0a2..fd37bcbfaab 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -31,6 +31,8 @@
#include "qemu/cutils.h"
#include "qemu/target-info.h"
#include "qom/object_interfaces.h"
+#include "qom/qom-qobject.h"
+#include "qobject/qobject.h"
#define MAX_IRQ 256
@@ -754,6 +756,50 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
new_ns = qemu_clock_advance_virtual_time(ns);
qtest_sendf(chr, "%s %"PRIi64"\n",
new_ns == ns ? "OK" : "FAIL", new_ns);
+ } else if (strcmp(words[0], "qom-tests") == 0) {
+ GSList *list, *l;
+
+ list = object_class_get_list(NULL, false);
+ for (l = list; l; l = l->next) {
+ ObjectClass *klass = l->data;
+ const char *type_name = object_class_get_name(klass);
+ Object *obj;
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+
+ obj = object_new_with_class(klass);
+ object_property_iter_init(&iter, obj);
+ while ((prop = object_property_iter_next(&iter))) {
+ QObject *value;
+ Error *local_err = NULL;
+
+ value = object_property_get_qobject(obj, prop->name,
+ &local_err);
+ if (local_err) {
+ error_report("qom-tests: %s.%s: get failed: %s",
+ type_name, prop->name,
+ error_get_pretty(local_err));
+ error_free(local_err);
+ continue;
+ }
+
+ if (prop->set) {
+ if (!object_property_set_qobject(obj, prop->name, value,
+ &local_err)) {
+ error_report("qom-tests: %s.%s: set failed: %s",
+ type_name, prop->name,
+ error_get_pretty(local_err));
+ error_free(local_err);
+ }
+ }
+
+ qobject_unref(value);
+ }
+
+ object_unref(obj);
+ }
+ g_slist_free(list);
+ qtest_send(chr, "OK\n");
} else if (process_command_cb && process_command_cb(chr, words)) {
/* Command got consumed by the callback handler */
} else {
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index b1e06ea364e..4e22c66b754 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -1137,6 +1137,12 @@ void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
qtest_rsp(s);
}
+void qtest_qom_tests(QTestState *s)
+{
+ qtest_sendf(s, "qom-tests\n");
+ qtest_rsp(s);
+}
+
static int64_t qtest_clock_rsp(QTestState *s)
{
gchar **words;
diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c
index 6421f2d9d9f..cf4c6b5add5 100644
--- a/tests/qtest/qom-test.c
+++ b/tests/qtest/qom-test.c
@@ -227,6 +227,17 @@ static void add_machine_test_case(const char *mname)
g_free(path);
}
+static void test_qom_qtests(void)
+{
+ QTestState *qts;
+
+ qts = qtest_initf("-machine none");
+
+ qtest_qom_tests(qts);
+
+ qtest_quit(qts);
+}
+
int main(int argc, char **argv)
{
char *v_env = getenv("V");
@@ -238,6 +249,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
+ qtest_add_func("qom/qom-qtests", test_qom_qtests);
return g_test_run();
}
--
2.54.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [GIT PULL v2 00/23] Fix various QOM object life-cycle issues
2026-06-06 5:15 [GIT PULL v2 00/23] Fix various QOM object life-cycle issues Marc-André Lureau
` (22 preceding siblings ...)
2026-06-06 5:15 ` [GIT PULL v2 23/23] qtest: add "qom-tests" command Marc-André Lureau
@ 2026-06-06 22:10 ` Stefan Hajnoczi
23 siblings, 0 replies; 25+ messages in thread
From: Stefan Hajnoczi @ 2026-06-06 22:10 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, stefanha
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread