From nobody Wed Aug 26 09:45:07 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1781168722; cv=none; d=zohomail.com; s=zohoarc; b=T5Gmd6Zg6Jw+/vDinS+XK16g+gICsE9VlDaCl8RUQKmgNgja1pE1HQed1De0VVRzGgMmdPdwof0RE/5eO0gGtjLFCAcR8A0Ej1lPqS0s+916GHkCeyya1VMDqxEbhMQG2I79ZBXzxhvvmQgtp8LqOzDSaVXhngquujhq7tp+Q8M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1781168722; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=wtIuehbACikmtRzKeZdlKQjVgxJxCKBEgIXdRAX00X8=; b=cc/NlyOIbVxwKh+XsatfWIDmGVdveWBgb4vvHK2dI9M9+Eg94o+JCX1NFT022uEnPiOpNktpVjExo7b7y4tY7pDESZxkyJkuboycJIMEz9nPP11dBVKCX50zLIsbxt68Z7pvJKw5P8wbMJBSUT4YUvUgajOCTS5BoY8a8Xbel8Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17811687220341020.6193103847771; Thu, 11 Jun 2026 02:05:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wXbLa-0002Sr-0d; Thu, 11 Jun 2026 05:05:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXbLY-0002S3-6I for qemu-devel@nongnu.org; Thu, 11 Jun 2026 05:05:08 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wXbLV-0004od-Q7 for qemu-devel@nongnu.org; Thu, 11 Jun 2026 05:05:07 -0400 Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-377-RcJESy1cMOmkz2_yGKugaQ-1; Thu, 11 Jun 2026 05:05:01 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8E2A41944AB0; Thu, 11 Jun 2026 09:05:00 +0000 (UTC) Received: from localhost (unknown [10.44.24.21]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3A4521954B10; Thu, 11 Jun 2026 09:04:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1781168705; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wtIuehbACikmtRzKeZdlKQjVgxJxCKBEgIXdRAX00X8=; b=aUHnZdW7l7ifOIqE8goVcgCZ18wEGBceDY4I2zEhwO9YRJjkuqyyrzjH6NuKRGnzFpzpO2 msNxfMkWX8rcyYU77Z8mzTczwWnXYfLVFnK6TpzfcTuglrAqMUY7MC0yf0zgjDlM9Xb4vr Kw+pimxAhctXnmBZ9BKEQ7XZZbx2YBM= X-MC-Unique: RcJESy1cMOmkz2_yGKugaQ-1 X-Mimecast-MFC-AGG-ID: RcJESy1cMOmkz2_yGKugaQ_1781168700 From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= Date: Thu, 11 Jun 2026 13:03:30 +0400 Subject: [PATCH v3 15/35] ui/spice: add cleanup on shutdown MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-b4-ui-v3-15-72bcbbea0fae@redhat.com> References: <20260611-b4-ui-v3-0-72bcbbea0fae@redhat.com> In-Reply-To: <20260611-b4-ui-v3-0-72bcbbea0fae@redhat.com> To: qemu-devel@nongnu.org Cc: Paolo Bonzini , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Pierrick Bouvier , Fabiano Rosas , Laurent Vivier , Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Peter Maydell , Akihiko Odaki , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Developer-Signature: v=1; a=openpgp-sha256; l=11898; i=marcandre.lureau@redhat.com; h=from:subject:message-id; bh=Ye9+Vgip4vwm6KSxEBhJWhIpcEVibFM6TefqtVC4tZc=; b=owEBbQKS/ZANAwAKAdro4Ql1lpzlAcsmYgBqKnnfeEQvYnpMGEXEZYs66aGUELJOCvuTryLjN L/gcIjW3aCJAjMEAAEKAB0WIQSHqb2TP4fGBtJ29i3a6OEJdZac5QUCaip53wAKCRDa6OEJdZac 5cTtEACatc+SM8skmUNdHvxeEcFjgw3yHl9M5qpIVN5tXJtiLc0gZFAxSNjrsx2g00sXpRmPGsQ dPsWqMZ8IL0oIWJGdzkQNkywzzMddT7Pk5rAvjQ6PP13PykdpB760DQ3XSomslMhVI23bh+NzBQ 0oUifK/tz/ra5Xq9AuGbp0hRlc3P7uB4RgVE3rXXUL6bcM93I7or5wUIzcbQgyEzO1ZUUFcHJ/l zum/6Lsc91ItmAWhKALRFEbA3yN8E+Bgaxj9dq246E1DShe7BGSikV94JpwXe488VzCLQbqAvwF rMbJS/zNR5r4te+7kPu9VLGr+MuCT8WxAcu03CjrFRnHMLK74uP/BoP3BphAuJCO2K7huxHZODV RPvkKfG08anolC0sJRn6Hx36zSi7Uiljp6DiKp9lAHekjZwd1nwrDMQ3SZZHlfMn8C60RUW9fGM mkIZlRHsyHGw3TKAgEFrPGn4K4QWMbtVmQqNefLAUoY9QJaKM1jkEn9HmW7OTzccvFU1Y4hG8Qy dRVtwJ1+VEpVDDyqXGx0uWXa/wJQY9eUR/tW5UNRQDH9JrOR14AJ+0kHj2GiH5JknkzMl/PS4q6 i0TaD6TXVaLk06H25Ib/MaYa0uSMxP1U/IQ/vUVcnVQR5/MXlxEV5W5V533XjUMG9GjoqpzQllf uoO4944s1B4HyFg== X-Developer-Key: i=marcandre.lureau@redhat.com; a=openpgp; fpr=87A9BD933F87C606D276F62DDAE8E10975969CE5 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=marcandre.lureau@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: 8 X-Spam_score: 0.8 X-Spam_bar: / X-Spam_report: (0.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.445, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1781168724084158500 SPICE resources were never freed on shutdown. Add per-subsystem cleanup (display, input, core) and call it from qemu_cleanup(). Move spice-module.c into libui so the qemu_spice ops table links with the rest of the UI code. Add an LSan suppression for a known spice-server leak. Reviewed-by: Daniel P. Berrang=C3=A9 Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/ui/qemu-spice-module.h | 1 + include/ui/qemu-spice.h | 2 ++ system/runstate.c | 4 ++++ ui/spice-core.c | 25 ++++++++++++++++++-- ui/spice-display.c | 52 ++++++++++++++++++++++++++++++++++++++= ++++ ui/spice-input.c | 52 ++++++++++++++++++++++++++++----------= ---- ui/spice-module.c | 5 ++++ scripts/lsan_suppressions.txt | 5 ++++ ui/meson.build | 4 ++-- 9 files changed, 129 insertions(+), 21 deletions(-) diff --git a/include/ui/qemu-spice-module.h b/include/ui/qemu-spice-module.h index 072efa0c834..bb0f8437c26 100644 --- a/include/ui/qemu-spice-module.h +++ b/include/ui/qemu-spice-module.h @@ -26,6 +26,7 @@ typedef struct SpiceInfo SpiceInfo; =20 struct QemuSpiceOps { void (*init)(void); + void (*cleanup)(void); void (*display_init)(void); int (*migrate_info)(const char *h, int p, int t, const char *s); int (*set_passwd)(const char *passwd, diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index 59a68cd9833..2cdf10f0313 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -27,7 +27,9 @@ #include "qemu/config-file.h" =20 void qemu_spice_input_init(void); +void qemu_spice_input_cleanup(void); void qemu_spice_display_init(void); +void qemu_spice_display_cleanup(void); void qemu_spice_display_init_done(void); bool qemu_spice_have_display_interface(QemuConsole *con); int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con); diff --git a/system/runstate.c b/system/runstate.c index 0e1cb3b4e67..d35fa270bd6 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -62,6 +62,7 @@ #include "system/system.h" #include "system/tpm.h" #include "ui/console.h" +#include "ui/qemu-spice-module.h" =20 #include "trace.h" =20 @@ -1048,6 +1049,9 @@ void qemu_cleanup(int status) user_creatable_cleanup(); #ifdef CONFIG_VNC vnc_cleanup(); +#endif +#ifdef CONFIG_SPICE + qemu_spice.cleanup(); #endif /* TODO: unref root container, check all devices are ok */ } diff --git a/ui/spice-core.c b/ui/spice-core.c index ef1c00134fa..1d2315f0b63 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -651,12 +651,15 @@ static void vm_change_state_handler(void *opaque, boo= l running, } } =20 +static VMChangeStateEntry *vm_change_entry; + void qemu_spice_display_init_done(void) { if (runstate_is_running()) { qemu_spice_display_start(); } - qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); + vm_change_entry =3D + qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); } =20 static void qemu_spice_init(void) @@ -894,7 +897,8 @@ static int qemu_spice_add_interface(SpiceBaseInstance *= sin) spice_server =3D spice_server_new(); spice_server_set_sasl_appname(spice_server, "qemu"); spice_server_init(spice_server, &core_interface); - qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); + vm_change_entry =3D + qemu_add_vm_change_state_handler(vm_change_state_handler, NULL= ); } =20 return spice_server_add_interface(spice_server, sin); @@ -1005,8 +1009,25 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay= *ssd) return spice_display_is_running; } =20 +static void qemu_spice_cleanup(void) +{ + if (!spice_server) { + return; + } + + qemu_spice_display_cleanup(); + qemu_spice_input_cleanup(); + migration_remove_notifier(&migration_state); + g_clear_pointer(&spice_consoles, g_slist_free); + g_clear_pointer(&auth_passwd, g_free); + g_clear_pointer(&spice_server, spice_server_destroy); + g_clear_pointer(&vm_change_entry, qemu_del_vm_change_state_handler); + using_spice =3D 0; +} + static struct QemuSpiceOps real_spice_ops =3D { .init =3D qemu_spice_init, + .cleanup =3D qemu_spice_cleanup, .display_init =3D qemu_spice_display_init, .migrate_info =3D qemu_spice_migrate_info, .set_passwd =3D qemu_spice_set_passwd, diff --git a/ui/spice-display.c b/ui/spice-display.c index e3716127203..75c7df7bb5e 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -34,6 +34,8 @@ bool spice_opengl; bool spice_remote_client; int spice_max_refresh_rate; =20 +static GPtrArray *spice_displays; + int qemu_spice_rect_is_empty(const QXLRect* r) { return r->top =3D=3D r->bottom || r->left =3D=3D r->right; @@ -1421,6 +1423,54 @@ static void qemu_spice_display_init_one(QemuConsole = *con) qemu_console_set_display_gl_ctx(con, &ssd->dgc); } qemu_console_register_listener(con, &ssd->dcl, ops); + g_ptr_array_add(spice_displays, ssd); +} + +void qemu_spice_display_cleanup(void) +{ + if (!spice_displays) { + return; + } + + for (guint i =3D 0; i < spice_displays->len; i++) { + SimpleSpiceDisplay *ssd =3D g_ptr_array_index(spice_displays, i); + SimpleSpiceUpdate *update; + + qemu_console_unregister_listener(&ssd->dcl); +#ifdef HAVE_SPICE_GL + if (spice_opengl) { + qemu_console_set_display_gl_ctx(ssd->dcl.con, NULL); + } +#endif + + if (ssd->ds) { + qemu_spice_destroy_host_primary(ssd); + } + qemu_spice_del_memslot(ssd, MEMSLOT_GROUP_HOST, 0); + spice_server_remove_interface(&ssd->qxl.base); + + while ((update =3D QTAILQ_FIRST(&ssd->updates)) !=3D NULL) { + QTAILQ_REMOVE(&ssd->updates, update, next); + qemu_spice_destroy_update(ssd, update); + } + g_clear_pointer(&ssd->ptr_define, g_free); + g_clear_pointer(&ssd->ptr_move, g_free); + g_clear_pointer(&ssd->cursor, cursor_unref); + g_clear_pointer(&ssd->surface, pixman_image_unref); + g_clear_pointer(&ssd->mirror, pixman_image_unref); + g_clear_pointer(&ssd->buf, g_free); +#ifdef HAVE_SPICE_GL + g_clear_pointer(&ssd->gl_unblock_bh, qemu_bh_delete); + g_clear_pointer(&ssd->gl_unblock_timer, timer_free); + g_clear_pointer(&ssd->gls, qemu_gl_fini_shader); + egl_fb_destroy(&ssd->guest_fb); + egl_fb_destroy(&ssd->blit_fb); + egl_fb_destroy(&ssd->cursor_fb); +#endif + qemu_mutex_destroy(&ssd->lock); + g_free(ssd); + } + g_clear_pointer(&spice_displays, g_ptr_array_unref); } =20 void qemu_spice_display_init(void) @@ -1431,6 +1481,8 @@ void qemu_spice_display_init(void) const char *str; int i; =20 + spice_displays =3D g_ptr_array_new(); + str =3D qemu_opt_get(opts, "display"); if (str) { int head =3D qemu_opt_get_number(opts, "head", 0); diff --git a/ui/spice-input.c b/ui/spice-input.c index f0bb915fd77..c975c1e2516 100644 --- a/ui/spice-input.c +++ b/ui/spice-input.c @@ -239,23 +239,41 @@ static void mouse_mode_notifier(Notifier *notifier, v= oid *data) pointer->absolute =3D is_absolute; } =20 +static QemuSpiceKbd *spice_kbd; +static QemuSpicePointer *spice_pointer; +static QEMUPutLEDEntry *spice_led; + void qemu_spice_input_init(void) { - QemuSpiceKbd *kbd; - QemuSpicePointer *pointer; - - kbd =3D g_malloc0(sizeof(*kbd)); - kbd->sin.base.sif =3D &kbd_interface.base; - qemu_spice.add_interface(&kbd->sin.base); - qemu_add_led_event_handler(kbd_leds, kbd); - - pointer =3D g_malloc0(sizeof(*pointer)); - pointer->mouse.base.sif =3D &mouse_interface.base; - pointer->tablet.base.sif =3D &tablet_interface.base; - qemu_spice.add_interface(&pointer->mouse.base); - - pointer->absolute =3D false; - pointer->mouse_mode.notify =3D mouse_mode_notifier; - qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode); - mouse_mode_notifier(&pointer->mouse_mode, NULL); + spice_kbd =3D g_new0(QemuSpiceKbd, 1); + spice_kbd->sin.base.sif =3D &kbd_interface.base; + qemu_spice.add_interface(&spice_kbd->sin.base); + spice_led =3D qemu_add_led_event_handler(kbd_leds, spice_kbd); + + spice_pointer =3D g_new0(QemuSpicePointer, 1); + spice_pointer->mouse.base.sif =3D &mouse_interface.base; + spice_pointer->tablet.base.sif =3D &tablet_interface.base; + qemu_spice.add_interface(&spice_pointer->mouse.base); + + spice_pointer->absolute =3D false; + spice_pointer->mouse_mode.notify =3D mouse_mode_notifier; + qemu_add_mouse_mode_change_notifier(&spice_pointer->mouse_mode); + mouse_mode_notifier(&spice_pointer->mouse_mode, NULL); +} + +void qemu_spice_input_cleanup(void) +{ + g_clear_pointer(&spice_led, qemu_remove_led_event_handler); + if (spice_pointer) { + qemu_remove_mouse_mode_change_notifier(&spice_pointer->mouse_mode); + if (spice_pointer->absolute) { + spice_server_remove_interface(&spice_pointer->tablet.base); + } + spice_server_remove_interface(&spice_pointer->mouse.base); + g_clear_pointer(&spice_pointer, g_free); + } + if (spice_kbd) { + spice_server_remove_interface(&spice_kbd->sin.base); + g_clear_pointer(&spice_kbd, g_free); + } } diff --git a/ui/spice-module.c b/ui/spice-module.c index 7651c85885f..1961060d128 100644 --- a/ui/spice-module.c +++ b/ui/spice-module.c @@ -62,6 +62,10 @@ static int qemu_spice_display_add_client_stub(int csock,= int skipauth, return -1; } =20 +static void qemu_spice_cleanup_stub(void) +{ +} + struct QemuSpiceOps qemu_spice =3D { .init =3D qemu_spice_init_stub, .display_init =3D qemu_spice_display_init_stub, @@ -69,6 +73,7 @@ struct QemuSpiceOps qemu_spice =3D { .set_passwd =3D qemu_spice_set_passwd_stub, .set_pw_expire =3D qemu_spice_set_pw_expire_stub, .display_add_client =3D qemu_spice_display_add_client_stub, + .cleanup =3D qemu_spice_cleanup_stub, }; =20 #ifdef CONFIG_SPICE diff --git a/scripts/lsan_suppressions.txt b/scripts/lsan_suppressions.txt index f3b827facff..2dd6581a650 100644 --- a/scripts/lsan_suppressions.txt +++ b/scripts/lsan_suppressions.txt @@ -20,3 +20,8 @@ leak:libfontconfig.so # https://github.com/GNOME/glib/blob/main/tools/glib.supp # This avoids false positive leak reports for the qga-ssh-test. leak:g_set_user_dirs + +# spice_server_add_interface allocates internal channel data that +# spice_server_destroy does not free +# https://gitlab.freedesktop.org/spice/spice/-/merge_requests/246 +leak:spice_server_add_interface diff --git a/ui/meson.build b/ui/meson.build index bb01f0728e2..ca903581abd 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -42,13 +42,14 @@ libui_sources =3D files( 'kbd-state.c', 'keymaps.c', 'qemu-pixman.c', + 'spice-module.c', 'vgafont.c', ) if pixman.found() libui_sources +=3D files('cp437.c', 'vt100.c') endif libui =3D static_library('qemuui', libui_sources + genh, - dependencies: [pixman], + dependencies: [pixman, spice_headers], build_by_default: false) ui =3D declare_dependency(objects: libui.extract_all_objects(recursive: fa= lse), dependencies: [pixman]) system_ss.add(png) @@ -65,7 +66,6 @@ system_ss.add(when: pixman, if_true: files('console-vc.c'= ), if_false: files('con if dbus_display system_ss.add(files('dbus-module.c')) endif -system_ss.add([spice_headers, files('spice-module.c')]) system_ss.add(when: spice_protocol, if_true: files('vdagent.c')) =20 if host_os =3D=3D 'linux' --=20 2.54.0