* [PATCH v3 01/24] ui/vt100: add vt100_fini() check
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 15:56 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 02/24] hw/pci: handle missing bus in prop_pci_busnr_get Marc-André Lureau
` (23 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
vt100_fini() is called unconditonally from qemu_text_console_finalize(),
but it may not have been vt100_init()/opened: fix the crash in that case.
Fixes: 8fa294482eb ("ui/console-vc: move VT100 state machine ...")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vt100.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ui/vt100.c b/ui/vt100.c
index e2fba822523..e5ad978bc8c 100644
--- a/ui/vt100.c
+++ b/ui/vt100.c
@@ -978,6 +978,9 @@ void vt100_init(QemuVT100 *vt,
void vt100_fini(QemuVT100 *vt)
{
+ if (!QTAILQ_IN_USE(vt, list)) {
+ return;
+ }
QTAILQ_REMOVE(&vt100s, vt, list);
fifo8_destroy(&vt->out_fifo);
g_free(vt->cells);
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread* [PATCH v3 02/24] hw/pci: handle missing bus in prop_pci_busnr_get
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
2026-05-16 7:59 ` [PATCH v3 01/24] ui/vt100: add vt100_fini() check Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:50 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 03/24] chardev/char-socket: handle NULL addr in char_socket_get_addr Marc-André Lureau
` (22 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 03/24] chardev/char-socket: handle NULL addr in char_socket_get_addr
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
2026-05-16 7:59 ` [PATCH v3 01/24] ui/vt100: add vt100_fini() check Marc-André Lureau
2026-05-16 7:59 ` [PATCH v3 02/24] hw/pci: handle missing bus in prop_pci_busnr_get Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:47 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 04/24] hw/pci-bridge: handle missing parent in prop_pxb_uid_get Marc-André Lureau
` (21 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 04/24] hw/pci-bridge: handle missing parent in prop_pxb_uid_get
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (2 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 03/24] chardev/char-socket: handle NULL addr in char_socket_get_addr Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:47 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 05/24] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters Marc-André Lureau
` (20 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 05/24] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (3 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 04/24] hw/pci-bridge: handle missing parent in prop_pxb_uid_get Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:48 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 06/24] hw/pci-host/q35: " Marc-André Lureau
` (19 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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>
---
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] 55+ messages in thread* Re: [PATCH v3 05/24] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters
2026-05-16 7:59 ` [PATCH v3 05/24] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters Marc-André Lureau
@ 2026-06-04 14:48 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 14:48 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:04AM +0400, Marc-André Lureau wrote:
> 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>
> ---
> hw/pci-host/i440fx.c | 15 +++++++++++++--
> 1 file changed, 13 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 06/24] hw/pci-host/q35: handle NULL bus in pci-hole64 getters
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (4 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 05/24] hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:49 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 07/24] hw/ipmi: reject NULL 'bmc' property rather than crash Marc-André Lureau
` (18 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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.
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] 55+ messages in thread* [PATCH v3 07/24] hw/ipmi: reject NULL 'bmc' property rather than crash
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (5 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 06/24] hw/pci-host/q35: " Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:01 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 08/24] hw/xlnx_dp: reject NULL 'dpdma' " Marc-André Lureau
` (17 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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] 55+ messages in thread* [PATCH v3 08/24] hw/xlnx_dp: reject NULL 'dpdma' property rather than crash
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (6 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 07/24] hw/ipmi: reject NULL 'bmc' property rather than crash Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:02 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 09/24] hw/intc/apic: move checks to realize() Marc-André Lureau
` (16 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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] 55+ messages in thread* [PATCH v3 09/24] hw/intc/apic: move checks to realize()
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (7 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 08/24] hw/xlnx_dp: reject NULL 'dpdma' " Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:03 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 10/24] backends/cryptodev-lkcf: skip cleanup when not initialized Marc-André Lureau
` (15 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* Re: [PATCH v3 09/24] hw/intc/apic: move checks to realize()
2026-05-16 7:59 ` [PATCH v3 09/24] hw/intc/apic: move checks to realize() Marc-André Lureau
@ 2026-06-04 16:03 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 16:03 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:08AM +0400, Marc-André Lureau wrote:
> 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")
> 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(-)
>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 10/24] backends/cryptodev-lkcf: skip cleanup when not initialized
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (8 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 09/24] hw/intc/apic: move checks to realize() Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:04 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 11/24] system/ioport: minor code simplification Marc-André Lureau
` (14 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 11/24] system/ioport: minor code simplification
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (9 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 10/24] backends/cryptodev-lkcf: skip cleanup when not initialized Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 15:06 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 12/24] hw/core/machine: free shim_filename on finalization Marc-André Lureau
` (13 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
Drop needless memset() and replace g_malloc0() with g_new().
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] 55+ messages in thread* [PATCH v3 12/24] hw/core/machine: free shim_filename on finalization
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (10 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 11/24] system/ioport: minor code simplification Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:50 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 13/24] net/filter: free old values in property setters Marc-André Lureau
` (12 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
machine_set_shim allocates shim_filename via g_strdup, but
machine_finalize did not free it.
Fixes: a5bd044b1579 ("x86/loader: add -shim option")
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 63baff859f3..95ddbf472b4 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1284,6 +1284,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] 55+ messages in thread* [PATCH v3 13/24] net/filter: free old values in property setters
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (11 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 12/24] hw/core/machine: free shim_filename on finalization Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:52 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 14/24] target/i386/sev: add finalize functions and fix leaking setters Marc-André Lureau
` (11 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 14/24] target/i386/sev: add finalize functions and fix leaking setters
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (12 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 13/24] net/filter: free old values in property setters Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:55 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 15/24] target/i386/kvm/tdx: free strings in tdx_guest_finalize Marc-André Lureau
` (10 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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: a9b4942f485b ("target/i386: add Secure Encrypted Virtualization (SEV) object")
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] 55+ messages in thread* Re: [PATCH v3 14/24] target/i386/sev: add finalize functions and fix leaking setters
2026-05-16 7:59 ` [PATCH v3 14/24] target/i386/sev: add finalize functions and fix leaking setters Marc-André Lureau
@ 2026-06-04 14:55 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 14:55 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:13AM +0400, Marc-André Lureau wrote:
> 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: a9b4942f485b ("target/i386: add Secure Encrypted Virtualization (SEV) object")
^^^ that trailing 'b' shouldn't be there
Should also reference 7b34df44260b391e33bc3acf1ced30019d9aadf1
for the SNP struct which came later.
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> target/i386/sev.c | 37 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 37 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 15/24] target/i386/kvm/tdx: free strings in tdx_guest_finalize
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (13 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 14/24] target/i386/sev: add finalize functions and fix leaking setters Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 14:56 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize Marc-André Lureau
` (9 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* Re: [PATCH v3 15/24] target/i386/kvm/tdx: free strings in tdx_guest_finalize
2026-05-16 7:59 ` [PATCH v3 15/24] target/i386/kvm/tdx: free strings in tdx_guest_finalize Marc-André Lureau
@ 2026-06-04 14:56 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 14:56 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:14AM +0400, Marc-André Lureau wrote:
> 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")
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> target/i386/kvm/tdx.c | 5 +++++
> 1 file changed, 5 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (14 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 15/24] target/i386/kvm/tdx: free strings in tdx_guest_finalize Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 15:01 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 17/24] hw/i386/pc: free pcspk on finalization Marc-André Lureau
` (8 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* Re: [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize
2026-05-16 7:59 ` [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize Marc-André Lureau
@ 2026-06-04 15:01 ` Daniel P. Berrangé
2026-06-04 20:18 ` Marc-André Lureau
0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 15:01 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:15AM +0400, Marc-André Lureau wrote:
> 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")
> 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);
> +}
Beyond these strings, nems->vnsm is initialized from
qdev_new(...) and I'm not seeing what frees that
device.
I presume the qom test at the end only exposed the
string leaks ?
> +
> 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
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread* Re: [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize
2026-06-04 15:01 ` Daniel P. Berrangé
@ 2026-06-04 20:18 ` Marc-André Lureau
2026-06-05 7:12 ` Daniel P. Berrangé
0 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-06-04 20:18 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, armbru
Hi
On Thu, Jun 4, 2026 at 7:01 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Sat, May 16, 2026 at 11:59:15AM +0400, Marc-André Lureau wrote:
> > 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")
> > 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);
> > +}
>
>
> Beyond these strings, nems->vnsm is initialized from
> qdev_new(...) and I'm not seeing what frees that
> device.
Correct, but it is followed by qdev_realize_and_unref(), thus it
doesn't own a reference.
>
> I presume the qom test at the end only exposed the
> string leaks ?
yes
thanks
>
>
> > +
> > 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
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> |: https://libvirt.org ~~ https://entangle-photo.org :|
> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>
^ permalink raw reply [flat|nested] 55+ messages in thread* Re: [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize
2026-06-04 20:18 ` Marc-André Lureau
@ 2026-06-05 7:12 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-05 7:12 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Fri, Jun 05, 2026 at 12:18:50AM +0400, Marc-André Lureau wrote:
> Hi
>
> On Thu, Jun 4, 2026 at 7:01 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
> >
> > On Sat, May 16, 2026 at 11:59:15AM +0400, Marc-André Lureau wrote:
> > > 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")
> > > 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);
> > > +}
> >
> >
> > Beyond these strings, nems->vnsm is initialized from
> > qdev_new(...) and I'm not seeing what frees that
> > device.
>
> Correct, but it is followed by qdev_realize_and_unref(), thus it
> doesn't own a reference.
Ah yes, in that case
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
>
> >
> > I presume the qom test at the end only exposed the
> > string leaks ?
>
> yes
>
> thanks
>
> >
> >
> > > +
> > > 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
> > >
> > >
> >
> > With regards,
> > Daniel
> > --
> > |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> > |: https://libvirt.org ~~ https://entangle-photo.org :|
> > |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
> >
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 17/24] hw/i386/pc: free pcspk on finalization
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (15 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 16/24] hw/i386/nitro_enclave: add instance finalize Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 15:02 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 18/24] hw/tpm: free PPI buffer " Marc-André Lureau
` (7 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 18/24] hw/tpm: free PPI buffer on finalization
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (16 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 17/24] hw/i386/pc: free pcspk on finalization Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-05-21 20:17 ` Arun Menon
2026-05-29 9:17 ` Peter Maydell
2026-05-16 7:59 ` [PATCH v3 19/24] hw/loongarch/virt: free flash devices and OEM strings " Marc-André Lureau
` (6 subsequent siblings)
24 siblings, 2 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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>
---
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 6bec30c36fc..3984228c42f 100644
--- a/hw/tpm/tpm_tis_sysbus.c
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -150,11 +150,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_init = 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] 55+ messages in thread* Re: [PATCH v3 18/24] hw/tpm: free PPI buffer on finalization
2026-05-16 7:59 ` [PATCH v3 18/24] hw/tpm: free PPI buffer " Marc-André Lureau
@ 2026-05-21 20:17 ` Arun Menon
2026-05-21 21:16 ` Marc-André Lureau
2026-05-29 9:17 ` Peter Maydell
1 sibling, 1 reply; 55+ messages in thread
From: Arun Menon @ 2026-05-21 20:17 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
Hi,
On Sat, May 16, 2026 at 11:59:17AM +0400, Marc-André Lureau wrote:
> 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>
> ---
> 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 6bec30c36fc..3984228c42f 100644
> --- a/hw/tpm/tpm_tis_sysbus.c
> +++ b/hw/tpm/tpm_tis_sysbus.c
> @@ -150,11 +150,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_init = tpm_tis_sysbus_finalize,
shouldn't this be .instance_finalize ?
> .class_init = tpm_tis_sysbus_class_init,
> .interfaces = (const InterfaceInfo[]) {
> { TYPE_TPM_IF },
>
> --
> 2.54.0
>
>
Regards,
Arun Menon
^ permalink raw reply [flat|nested] 55+ messages in thread* Re: [PATCH v3 18/24] hw/tpm: free PPI buffer on finalization
2026-05-21 20:17 ` Arun Menon
@ 2026-05-21 21:16 ` Marc-André Lureau
0 siblings, 0 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-21 21:16 UTC (permalink / raw)
To: Arun Menon; +Cc: qemu-devel, armbru
Hi
On Fri, May 22, 2026 at 12:17 AM Arun Menon <armenon@redhat.com> wrote:
>
> Hi,
>
> On Sat, May 16, 2026 at 11:59:17AM +0400, Marc-André Lureau wrote:
> > 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>
> > ---
> > 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 6bec30c36fc..3984228c42f 100644
> > --- a/hw/tpm/tpm_tis_sysbus.c
> > +++ b/hw/tpm/tpm_tis_sysbus.c
> > @@ -150,11 +150,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_init = tpm_tis_sysbus_finalize,
>
> shouldn't this be .instance_finalize ?
Good catch! Weird, it made it through the test, Ill check!
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v3 18/24] hw/tpm: free PPI buffer on finalization
2026-05-16 7:59 ` [PATCH v3 18/24] hw/tpm: free PPI buffer " Marc-André Lureau
2026-05-21 20:17 ` Arun Menon
@ 2026-05-29 9:17 ` Peter Maydell
2026-05-29 10:55 ` Marc-André Lureau
1 sibling, 1 reply; 55+ messages in thread
From: Peter Maydell @ 2026-05-29 9:17 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, 16 May 2026 at 09:03, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> 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>
> ---
> 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 6bec30c36fc..3984228c42f 100644
> --- a/hw/tpm/tpm_tis_sysbus.c
> +++ b/hw/tpm/tpm_tis_sysbus.c
> @@ -150,11 +150,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);
> +}
https://patchew.org/QEMU/20260528093123.55403-1-mbawa@redhat.com/
(likely to land upstream shortly) moves the allocation to
the realize function, so maybe this free should also be moved to
unrealize ?
-- PMM
^ permalink raw reply [flat|nested] 55+ messages in thread* Re: [PATCH v3 18/24] hw/tpm: free PPI buffer on finalization
2026-05-29 9:17 ` Peter Maydell
@ 2026-05-29 10:55 ` Marc-André Lureau
0 siblings, 0 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-29 10:55 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel, armbru
Hi
On Fri, May 29, 2026 at 1:17 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Sat, 16 May 2026 at 09:03, Marc-André Lureau
> <marcandre.lureau@redhat.com> wrote:
> >
> > 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>
> > ---
> > 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 6bec30c36fc..3984228c42f 100644
> > --- a/hw/tpm/tpm_tis_sysbus.c
> > +++ b/hw/tpm/tpm_tis_sysbus.c
> > @@ -150,11 +150,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);
> > +}
>
> https://patchew.org/QEMU/20260528093123.55403-1-mbawa@redhat.com/
> (likely to land upstream shortly) moves the allocation to
> the realize function, so maybe this free should also be moved to
> unrealize ?
yes, it might be worth getting this reviewed & merged before it rots.
Most patches are trivial, but if we don't have the time/interest,
should I take the responsability and send a MR?
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 19/24] hw/loongarch/virt: free flash devices and OEM strings on finalization
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (17 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 18/24] hw/tpm: free PPI buffer " Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-05-16 7:59 ` [PATCH v3 20/24] hw/ppc/spapr: free host_model and host_serial " Marc-André Lureau
` (5 subsequent siblings)
24 siblings, 0 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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")
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] 55+ messages in thread* [PATCH v3 20/24] hw/ppc/spapr: free host_model and host_serial on finalization
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (18 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 19/24] hw/loongarch/virt: free flash devices and OEM strings " Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:05 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 21/24] target/riscv: fix general_user_opts hash table leak Marc-André Lureau
` (4 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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)")
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 d40af312fae..4ec0a7d20b8 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] 55+ messages in thread* [PATCH v3 21/24] target/riscv: fix general_user_opts hash table leak
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (19 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 20/24] hw/ppc/spapr: free host_model and host_serial " Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-03 1:01 ` Alistair Francis
2026-05-16 7:59 ` [PATCH v3 22/24] target/riscv: use hash table as set for user_options Marc-André Lureau
` (3 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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[]")
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 | 6 +++---
3 files changed, 37 insertions(+), 25 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index fae839cade4..86a38a7288b 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -546,6 +546,7 @@ struct ArchCPU {
uint32_t pmu_avail_ctrs;
/* Mapping of events to counters */
GHashTable *pmu_event_ctr_map;
+ GHashTable *user_options;
const GPtrArray *decoders;
};
@@ -619,7 +620,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 506a018d52b..bbdc9d8f5de 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
@@ -1103,7 +1102,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
@@ -1453,7 +1452,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,
@@ -1495,7 +1494,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;
}
@@ -1527,7 +1526,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;
}
@@ -1559,7 +1558,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;
}
@@ -1599,7 +1598,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;
}
@@ -1637,7 +1636,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;
}
@@ -1710,7 +1709,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;
}
@@ -1744,7 +1743,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;
}
@@ -1787,7 +1786,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;
}
@@ -1828,7 +1827,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;
}
@@ -1864,7 +1863,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;
}
@@ -1900,7 +1899,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;
}
@@ -1936,7 +1935,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;
}
@@ -2975,6 +2974,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,
@@ -2982,6 +2992,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 b047ffa9c0c..e0241870ada 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -2025,7 +2025,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);
@@ -2044,7 +2044,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);
@@ -2063,7 +2063,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] 55+ messages in thread* Re: [PATCH v3 21/24] target/riscv: fix general_user_opts hash table leak
2026-05-16 7:59 ` [PATCH v3 21/24] target/riscv: fix general_user_opts hash table leak Marc-André Lureau
@ 2026-06-03 1:01 ` Alistair Francis
0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-06-03 1:01 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 6:02 PM Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> 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[]")
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> target/riscv/cpu.h | 3 ++-
> target/riscv/cpu.c | 53 ++++++++++++++++++++++++++++------------------
> target/riscv/kvm/kvm-cpu.c | 6 +++---
> 3 files changed, 37 insertions(+), 25 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index fae839cade4..86a38a7288b 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -546,6 +546,7 @@ struct ArchCPU {
> uint32_t pmu_avail_ctrs;
> /* Mapping of events to counters */
> GHashTable *pmu_event_ctr_map;
> + GHashTable *user_options;
> const GPtrArray *decoders;
> };
>
> @@ -619,7 +620,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 506a018d52b..bbdc9d8f5de 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
> @@ -1103,7 +1102,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
> @@ -1453,7 +1452,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,
> @@ -1495,7 +1494,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;
> }
>
> @@ -1527,7 +1526,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;
> }
>
> @@ -1559,7 +1558,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;
> }
>
> @@ -1599,7 +1598,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;
> }
>
> @@ -1637,7 +1636,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;
> }
>
> @@ -1710,7 +1709,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;
> }
>
> @@ -1744,7 +1743,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;
> }
>
> @@ -1787,7 +1786,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;
> }
>
> @@ -1828,7 +1827,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;
> }
>
> @@ -1864,7 +1863,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;
> }
>
> @@ -1900,7 +1899,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;
> }
>
> @@ -1936,7 +1935,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;
> }
>
> @@ -2975,6 +2974,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,
> @@ -2982,6 +2992,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 b047ffa9c0c..e0241870ada 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -2025,7 +2025,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);
> @@ -2044,7 +2044,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);
> @@ -2063,7 +2063,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 [flat|nested] 55+ messages in thread
* [PATCH v3 22/24] target/riscv: use hash table as set for user_options
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (20 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 21/24] target/riscv: fix general_user_opts hash table leak Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-03 1:02 ` Alistair Francis
2026-05-16 7:59 ` [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data Marc-André Lureau
` (2 subsequent siblings)
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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.
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 bbdc9d8f5de..6adba597969 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)
@@ -1452,7 +1450,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,
@@ -1494,7 +1492,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;
}
@@ -1526,7 +1524,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;
}
@@ -1558,7 +1556,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;
}
@@ -1598,7 +1596,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;
}
@@ -1636,7 +1634,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;
}
@@ -1709,7 +1707,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;
}
@@ -1743,7 +1741,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;
}
@@ -1786,7 +1784,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;
}
@@ -1827,7 +1825,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;
}
@@ -1863,7 +1861,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;
}
@@ -1899,7 +1897,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;
}
@@ -1935,7 +1933,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] 55+ messages in thread* Re: [PATCH v3 22/24] target/riscv: use hash table as set for user_options
2026-05-16 7:59 ` [PATCH v3 22/24] target/riscv: use hash table as set for user_options Marc-André Lureau
@ 2026-06-03 1:02 ` Alistair Francis
0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-06-03 1:02 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 6:02 PM Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> 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 bbdc9d8f5de..6adba597969 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)
> @@ -1452,7 +1450,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,
> @@ -1494,7 +1492,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;
> }
>
> @@ -1526,7 +1524,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;
> }
>
> @@ -1558,7 +1556,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;
> }
>
> @@ -1598,7 +1596,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;
> }
>
> @@ -1636,7 +1634,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;
> }
>
> @@ -1709,7 +1707,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;
> }
>
> @@ -1743,7 +1741,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;
> }
>
> @@ -1786,7 +1784,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;
> }
>
> @@ -1827,7 +1825,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;
> }
>
> @@ -1863,7 +1861,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;
> }
>
> @@ -1899,7 +1897,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;
> }
>
> @@ -1935,7 +1933,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 [flat|nested] 55+ messages in thread
* [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (21 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 22/24] target/riscv: use hash table as set for user_options Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:10 ` Daniel P. Berrangé
2026-05-16 7:59 ` [PATCH v3 24/24] qtest: add "qom-tests" command Marc-André Lureau
2026-05-20 13:34 ` [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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.
Fixes: 3746d5c15e70 ("hw/i2c: add support for PMBus")
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/i2c/pmbus_device.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
index 853dc4b4342..861f5b4fb63 100644
--- a/hw/i2c/pmbus_device.c
+++ b/hw/i2c/pmbus_device.c
@@ -23,8 +23,8 @@ 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) ? (uint32_t)x : 0;
}
uint16_t pmbus_data2linear_mode(uint16_t value, int exp)
--
2.54.0
^ permalink raw reply related [flat|nested] 55+ messages in thread* Re: [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data
2026-05-16 7:59 ` [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data Marc-André Lureau
@ 2026-06-04 16:10 ` Daniel P. Berrangé
2026-06-04 20:34 ` Marc-André Lureau
0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrangé @ 2026-06-04 16:10 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, armbru
On Sat, May 16, 2026 at 11:59:22AM +0400, Marc-André Lureau wrote:
> 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.
>
> Fixes: 3746d5c15e70 ("hw/i2c: add support for PMBus")
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> hw/i2c/pmbus_device.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
> index 853dc4b4342..861f5b4fb63 100644
> --- a/hw/i2c/pmbus_device.c
> +++ b/hw/i2c/pmbus_device.c
> @@ -23,8 +23,8 @@ 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) ? (uint32_t)x : 0;
Couldn't 'x' exceed G_MAXUINT32 and thus truncate here which
while not undefined would still seem undesirable ? If so, then
perhaps
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
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 55+ messages in thread* Re: [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data
2026-06-04 16:10 ` Daniel P. Berrangé
@ 2026-06-04 20:34 ` Marc-André Lureau
0 siblings, 0 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-06-04 20:34 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel, armbru
Hi
On Thu, Jun 4, 2026 at 8:11 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Sat, May 16, 2026 at 11:59:22AM +0400, Marc-André Lureau wrote:
> > 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.
> >
> > Fixes: 3746d5c15e70 ("hw/i2c: add support for PMBus")
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > hw/i2c/pmbus_device.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c
> > index 853dc4b4342..861f5b4fb63 100644
> > --- a/hw/i2c/pmbus_device.c
> > +++ b/hw/i2c/pmbus_device.c
> > @@ -23,8 +23,8 @@ 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) ? (uint32_t)x : 0;
>
> Couldn't 'x' exceed G_MAXUINT32 and thus truncate here which
> while not undefined would still seem undesirable ? If so, then
> perhaps
>
> return (x > 0
> ? (x < G_MAXUINT32 ? (uint32_t)x : G_MAXUINT32)
> : 0);
>
> ?
>
Yes, applied.
thanks
> > }
> >
> > uint16_t pmbus_data2linear_mode(uint16_t value, int exp)
> >
> > --
> > 2.54.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> |: https://libvirt.org ~~ https://entangle-photo.org :|
> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v3 24/24] qtest: add "qom-tests" command
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (22 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 23/24] hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data Marc-André Lureau
@ 2026-05-16 7:59 ` Marc-André Lureau
2026-06-04 16:14 ` Daniel P. Berrangé
2026-05-20 13:34 ` [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
24 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-16 7:59 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru, Marc-André Lureau
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.
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 a79d10d1361..a44a581a518 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] 55+ messages in thread* Re: [PATCH v3 00/24] Fix various QOM object life-cycle issues
2026-05-16 7:58 [PATCH v3 00/24] Fix various QOM object life-cycle issues Marc-André Lureau
` (23 preceding siblings ...)
2026-05-16 7:59 ` [PATCH v3 24/24] qtest: add "qom-tests" command Marc-André Lureau
@ 2026-05-20 13:34 ` Marc-André Lureau
24 siblings, 0 replies; 55+ messages in thread
From: Marc-André Lureau @ 2026-05-20 13:34 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Markus Armbruster
Hi
On Sat, May 16, 2026 at 12:00 PM Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
>
> Hi,
>
> After Markus's "Several QOM objects crash on introspection" report, I
> started writing some unit test.
>
> This series adds a new "qom-tests" qtest command that exercises basic QOM
> object life-cycle: it instantiates all non-abstract object types, gets/sets
> their properties, and unrefs them. This quickly surfaces leaks and crashes
> that could otherwise be triggered at runtime via QMP qom commands.
>
ping
> The bulk of the series fixes the issues found by this test and ASan
> help. Some of the patches are redundant with patches sent earlier on the
> ML and marked as RFC, they should naturally be dropped during rebases,
> but are added for completeness and to make sure CI pass after this
> series in the meantime.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> Changes in v3:
> - update "hw/ipmi: reject NULL 'bmc'" & "hw/xlnx_dp: reject NULL
> 'dpdma'"
> - fixed user-only build in target/riscv patch
> - add "ui/vt100: add vt100_fini() check" patch
> - rebased after PR with first half of series patches landed
> - Link to v2: https://lore.kernel.org/qemu-devel/20260504-qom-tests-v2-0-ef7e3dc94f7a@redhat.com
>
> Changes in v2:
> - tweak error messages
> - drop "qom: skip link property check callback", instead
> added two patches to avoid crash on NULL link check, and doc update
> - drop "RFC system/ioport" in favour of Peter Xu fix
> - added "hw/fsi: move OPBus qbus_init() to instance_init" to address TODO comment
> - added "target/riscv: use hash table as set for user_options"
> - gather a-b/r-b trailers
> - Link to v1: https://lore.kernel.org/qemu-devel/20260427-qom-tests-v1-0-c413f3605311@redhat.com
>
> ---
> Marc-André Lureau (24):
> ui/vt100: add vt100_fini() check
> hw/pci: handle missing bus in prop_pci_busnr_get
> chardev/char-socket: handle NULL addr in char_socket_get_addr
> hw/pci-bridge: handle missing parent in prop_pxb_uid_get
> hw/pci-host/i440fx: handle NULL bus in pci-hole64 getters
> hw/pci-host/q35: handle NULL bus in pci-hole64 getters
> hw/ipmi: reject NULL 'bmc' property rather than crash
> hw/xlnx_dp: reject NULL 'dpdma' property rather than crash
> hw/intc/apic: move checks to realize()
> backends/cryptodev-lkcf: skip cleanup when not initialized
> system/ioport: minor code simplification
> hw/core/machine: free shim_filename on finalization
> net/filter: free old values in property setters
> target/i386/sev: add finalize functions and fix leaking setters
> target/i386/kvm/tdx: free strings in tdx_guest_finalize
> hw/i386/nitro_enclave: add instance finalize
> hw/i386/pc: free pcspk on finalization
> hw/tpm: free PPI buffer on finalization
> hw/loongarch/virt: free flash devices and OEM strings on finalization
> hw/ppc/spapr: free host_model and host_serial on finalization
> target/riscv: fix general_user_opts hash table leak
> target/riscv: use hash table as set for user_options
> hw/i2c/pmbus: fix undefined behavior in pmbus_direct_mode2data
> qtest: add "qom-tests" command
>
> target/riscv/cpu.h | 3 ++-
> tests/qtest/libqtest.h | 8 ++++++
> backends/cryptodev-lkcf.c | 4 +++
> chardev/char-socket.c | 4 +++
> hw/core/machine.c | 1 +
> hw/display/xlnx_dp.c | 6 +++++
> hw/i2c/pmbus_device.c | 4 +--
> hw/i386/nitro_enclave.c | 11 ++++++++
> hw/i386/pc.c | 10 +++++++
> hw/intc/apic_common.c | 23 +++++++++-------
> hw/ipmi/ipmi.c | 8 +++++-
> hw/loongarch/virt.c | 14 ++++++++++
> hw/pci-bridge/pci_expander_bridge.c | 8 +++++-
> hw/pci-host/i440fx.c | 15 +++++++++--
> hw/pci-host/q35.c | 15 +++++++++--
> hw/pci/pci.c | 11 ++++++--
> hw/ppc/spapr.c | 2 ++
> hw/tpm/tpm_tis_sysbus.c | 9 +++++++
> net/filter.c | 2 ++
> system/ioport.c | 3 +--
> system/qtest.c | 46 ++++++++++++++++++++++++++++++++
> target/i386/cpu-apic.c | 6 +----
> target/i386/kvm/tdx.c | 5 ++++
> target/i386/sev.c | 37 ++++++++++++++++++++++++++
> target/riscv/cpu.c | 53 ++++++++++++++++++++++---------------
> target/riscv/kvm/kvm-cpu.c | 6 ++---
> tests/qtest/libqtest.c | 6 +++++
> tests/qtest/qom-test.c | 12 +++++++++
> ui/vt100.c | 3 +++
> 29 files changed, 282 insertions(+), 53 deletions(-)
> ---
> base-commit: 0bbb0c2b65db64c161f91d10a89269e6d319d2a7
> change-id: 20260427-qom-tests-9dcf3b969411
>
> Best regards,
> --
> Marc-André Lureau <marcandre.lureau@redhat.com>
>
>
^ permalink raw reply [flat|nested] 55+ messages in thread