cxl_init_cci() allocates a QEMUTimer via timer_new_ms() but
cxl_destroy_cci() never frees it.  This leaks a timer object on every
device exit path and, more critically, on every device reset cycle since
the secondary CCIs (vdm_fm_owned_ld_mctp_cci, ld0_cci) are destroyed
and re-initialized each time ct3d_reset() runs.

Free the timer with timer_free(), which cancels any pending expiry via
timer_del() internally and tolerates a NULL pointer, then clear the
field so that a repeated timer_free() on the same CCI is a safe no-op.
(The function as a whole is not idempotent: it also calls
qemu_mutex_destroy(), which asserts on an already-destroyed mutex.
Callers must not invoke cxl_destroy_cci() twice; the .initialized guard
added in the next patch enforces that.)

Fixes: 98cbac128f1c ("hw/cxl: Support aborting background commands")
Cc: [email protected]
Signed-off-by: Junjie Cao <[email protected]>
---
 hw/cxl/cxl-mailbox-utils.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 20e0b7e476..18a455e89c 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -4770,6 +4770,8 @@ void cxl_init_cci(CXLCCI *cci, size_t payload_max)
 
 void cxl_destroy_cci(CXLCCI *cci)
 {
+    timer_free(cci->bg.timer);
+    cci->bg.timer = NULL;
     qemu_mutex_destroy(&cci->bg.lock);
     cci->initialized = false;
 }
-- 
2.43.0


Reply via email to