@samitouri / QOSamiQemu / commits / 1f9c9387b0

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);