Commit 1f9c9387b0 for qemu.org
commit 1f9c9387b00183865121d01ae09de0423a840410
Author: Marc-André Lureau <marcandre.lureau@redhat.com>
Date: Tue Feb 24 16:05:58 2026 +0100
ui/vnc: fix vnc_display_init() leak on failure
Do not add the display state to the vnc list, if the initialization
failed. Add vnc_display_free(), to free the display state and associated
data in such case. The function is meant to be public and reused in the
following changes.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
diff --git a/ui/vnc.c b/ui/vnc.c
index d5d92c0d99..37ebd1a534 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3424,6 +3424,8 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
}
+static void vnc_display_free(VncDisplay *vd);
+
void vnc_display_init(const char *id, Error **errp)
{
VncDisplay *vd;
@@ -3433,8 +3435,9 @@ void vnc_display_init(const char *id, Error **errp)
}
vd = g_malloc0(sizeof(*vd));
+ qemu_mutex_init(&vd->mutex);
vd->id = g_strdup(id);
- QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
+ vd->dcl.ops = &dcl_ops;
QTAILQ_INIT(&vd->clients);
vd->expires = TIME_MAX;
@@ -3448,22 +3451,22 @@ void vnc_display_init(const char *id, Error **errp)
}
if (!vd->kbd_layout) {
+ vnc_display_free(vd);
return;
}
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
vd->connections_limit = 32;
- qemu_mutex_init(&vd->mutex);
vnc_start_worker_thread();
- vd->dcl.ops = &dcl_ops;
register_displaychangelistener(&vd->dcl);
vd->kbd = qkbd_state_init(vd->dcl.con);
vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
&vmstate_change_handler, vd);
-}
+ QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
+}
static void vnc_display_close(VncDisplay *vd)
{
@@ -3507,6 +3510,28 @@ static void vnc_display_close(VncDisplay *vd)
#endif
}
+static void vnc_display_free(VncDisplay *vd)
+{
+ if (!vd) {
+ return;
+ }
+
+ assert(QTAILQ_EMPTY(&vd->clients));
+
+ vnc_display_close(vd);
+ unregister_displaychangelistener(&vd->dcl);
+ qkbd_state_free(vd->kbd);
+ qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
+ kbd_layout_free(vd->kbd_layout);
+ qemu_mutex_destroy(&vd->mutex);
+ if (QTAILQ_IN_USE(vd, next)) {
+ QTAILQ_REMOVE(&vnc_displays, vd, next);
+ }
+ g_free(vd->id);
+ g_free(vd);
+}
+
+
int vnc_display_password(const char *id, const char *password, Error **errp)
{
VncDisplay *vd = vnc_display_find(id);