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>
Marc-André Lureau committed
Feb 24, 2026 at 16:05 UTC
1f9c9387b00183865121d01ae09de0423a840410
1 file changed
+29
-4
ui/vnc.c
+29
-4
@@ -3424,6 +3424,8 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
3424
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
3425
}
3426
3427
+static void vnc_display_free(VncDisplay *vd);
3428
+
3429
void vnc_display_init(const char *id, Error **errp)
3430
{
3431
VncDisplay *vd;
@@ -3433,8 +3435,9 @@ void vnc_display_init(const char *id, Error **errp)
3435
}
3436
vd = g_malloc0(sizeof(*vd));
3437
3438
+ qemu_mutex_init(&vd->mutex);
3439
vd->id = g_strdup(id);
3437
- QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
3440
+ vd->dcl.ops = &dcl_ops;
3441
3442
QTAILQ_INIT(&vd->clients);
3443
vd->expires = TIME_MAX;
@@ -3448,22 +3451,22 @@ void vnc_display_init(const char *id, Error **errp)
3451
}
3452
3453
if (!vd->kbd_layout) {
3454
+ vnc_display_free(vd);
3455
return;
3456
}
3457
3458
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3459
vd->connections_limit = 32;
3460
3457
- qemu_mutex_init(&vd->mutex);
3461
vnc_start_worker_thread();
3462
3460
- vd->dcl.ops = &dcl_ops;
3463
register_displaychangelistener(&vd->dcl);
3464
vd->kbd = qkbd_state_init(vd->dcl.con);
3465
vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
3466
&vmstate_change_handler, vd);
3465
-}
3467
3468
+ QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
3469
+}
3470
3471
static void vnc_display_close(VncDisplay *vd)
3472
{
@@ -3507,6 +3510,28 @@ static void vnc_display_close(VncDisplay *vd)
3510
#endif
3511
}
3512
3513
+static void vnc_display_free(VncDisplay *vd)
3514
+{
3515
+ if (!vd) {
3516
+ return;
3517
+ }
3518
+
3519
+ assert(QTAILQ_EMPTY(&vd->clients));
3520
+
3521
+ vnc_display_close(vd);
3522
+ unregister_displaychangelistener(&vd->dcl);
3523
+ qkbd_state_free(vd->kbd);
3524
+ qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
3525
+ kbd_layout_free(vd->kbd_layout);
3526
+ qemu_mutex_destroy(&vd->mutex);
3527
+ if (QTAILQ_IN_USE(vd, next)) {
3528
+ QTAILQ_REMOVE(&vnc_displays, vd, next);
3529
+ }
3530
+ g_free(vd->id);
3531
+ g_free(vd);
3532
+}
3533
+
3534
+
3535
int vnc_display_password(const char *id, const char *password, Error **errp)
3536
{
3537
VncDisplay *vd = vnc_display_find(id);