summaryrefslogtreecommitdiff
path: root/app-emulation/spice/files/spice-0.16.0-fix-qemu-11.1-crash.patch
blob: a03a971ddae60b4be0f9d45976138f2c4b715a7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
https://bugs.gentoo.org/985055
https://gitlab.com/qemu-project/qemu/-/work_items/4371
https://gitlab.freedesktop.org/spice/spice/-/merge_requests/246
https://gitlab.freedesktop.org/spice/spice/-/commit/c3efe69ecdcb6c1b9d73560d0cfdf88f109f2395

From c3efe69ecdcb6c1b9d73560d0cfdf88f109f2395 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Fri, 22 May 2026 21:47:17 +0400
Subject: [PATCH] inputs: Fix keyboard and mouse state leaks on interface
 removal
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

SpiceKbdState and SpiceMouseState allocated by set_keyboard()/set_mouse()
were never freed — remove_interface() had no handler for KEYBOARD or MOUSE
types, and the InputsChannel destructor only cleaned up the tablet.

Add detach_keyboard()/detach_mouse() following the existing detach_tablet()
pattern, call them from the destructor and from remove_interface().

Also give SpiceMouseState a RedsState back-pointer (replacing the dummy
field) so remove_interface() can locate the server, matching the tablet
state design.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
--- a/server/inputs-channel.cpp
+++ b/server/inputs-channel.cpp
@@ -56,12 +56,14 @@ static SpiceKbdState* spice_kbd_state_new(InputsChannel *inputs)
 }
 
 struct SpiceMouseState {
-    int dummy;
+    RedsState *reds;
 };
 
-static SpiceMouseState* spice_mouse_state_new()
+static SpiceMouseState* spice_mouse_state_new(RedsState *reds)
 {
-    return g_new0(SpiceMouseState, 1);
+    auto st = g_new0(SpiceMouseState, 1);
+    st->reds = reds;
+    return st;
 }
 
 struct SpiceTabletState {
@@ -85,6 +87,16 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *st)
     return st->reds;
 }
 
+RedsState* spice_kbd_state_get_server(SpiceKbdState *st)
+{
+    return st->inputs->get_server();
+}
+
+RedsState* spice_mouse_state_get_server(SpiceMouseState *st)
+{
+    return st->reds;
+}
+
 struct RedKeyModifiersPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_KEY_MODIFIERS> {
     explicit RedKeyModifiersPipeItem(uint8_t modifiers);
     uint8_t modifiers;
@@ -530,6 +542,8 @@ InputsChannel::InputsChannel(RedsState *reds):
 
 InputsChannel::~InputsChannel()
 {
+    detach_keyboard(keyboard);
+    detach_mouse(mouse);
     detach_tablet(tablet);
     red_timer_remove(key_modifiers_timer);
 }
@@ -552,7 +566,7 @@ int InputsChannel::set_mouse(SpiceMouseInstance *new_mouse)
         return -1;
     }
     mouse = new_mouse;
-    mouse->st = spice_mouse_state_new();
+    mouse->st = spice_mouse_state_new(get_server());
     return 0;
 }
 
@@ -581,6 +595,24 @@ void InputsChannel::detach_tablet(SpiceTabletInstance *old_tablet)
     tablet = nullptr;
 }
 
+void InputsChannel::detach_keyboard(SpiceKbdInstance *old_keyboard)
+{
+    if (old_keyboard != nullptr && old_keyboard == keyboard) {
+        g_free(old_keyboard->st);
+        old_keyboard->st = nullptr;
+    }
+    keyboard = nullptr;
+}
+
+void InputsChannel::detach_mouse(SpiceMouseInstance *old_mouse)
+{
+    if (old_mouse != nullptr && old_mouse == mouse) {
+        g_free(old_mouse->st);
+        old_mouse->st = nullptr;
+    }
+    mouse = nullptr;
+}
+
 bool InputsChannel::is_src_during_migrate() const
 {
     return src_during_migrate;
--- a/server/inputs-channel.h
+++ b/server/inputs-channel.h
@@ -46,6 +46,8 @@ public:
     int set_tablet(SpiceTabletInstance *tablet);
     bool has_tablet() const;
     void detach_tablet(SpiceTabletInstance *tablet);
+    void detach_keyboard(SpiceKbdInstance *keyboard);
+    void detach_mouse(SpiceMouseInstance *mouse);
 
 private:
     VDAgentMouseState mouse_state;
@@ -77,6 +79,8 @@ private:
 red::shared_ptr<InputsChannel> inputs_channel_new(RedsState *reds);
 
 RedsState *spice_tablet_state_get_server(SpiceTabletState *st);
+RedsState *spice_kbd_state_get_server(SpiceKbdState *st);
+RedsState *spice_mouse_state_get_server(SpiceMouseState *st);
 
 #include "pop-visibility.h"
 
--- a/server/reds.cpp
+++ b/server/reds.cpp
@@ -3360,7 +3360,19 @@ SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin)
     g_return_val_if_fail(sin != nullptr, -1);
 
     base_interface = sin->sif;
-    if (strcmp(base_interface->type, SPICE_INTERFACE_TABLET) == 0) {
+    if (strcmp(base_interface->type, SPICE_INTERFACE_KEYBOARD) == 0) {
+        SpiceKbdInstance *kbd = SPICE_UPCAST(SpiceKbdInstance, sin);
+        g_return_val_if_fail(kbd->st != nullptr, -1);
+        reds = spice_kbd_state_get_server(kbd->st);
+        spice_debug("remove SPICE_INTERFACE_KEYBOARD");
+        reds->inputs_channel->detach_keyboard(kbd);
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_MOUSE) == 0) {
+        SpiceMouseInstance *mouse = SPICE_UPCAST(SpiceMouseInstance, sin);
+        g_return_val_if_fail(mouse->st != nullptr, -1);
+        reds = spice_mouse_state_get_server(mouse->st);
+        spice_debug("remove SPICE_INTERFACE_MOUSE");
+        reds->inputs_channel->detach_mouse(mouse);
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_TABLET) == 0) {
         SpiceTabletInstance *tablet = SPICE_UPCAST(SpiceTabletInstance, sin);
         g_return_val_if_fail(tablet->st != nullptr, -1);
         reds = spice_tablet_state_get_server(tablet->st);
@@ -3387,7 +3399,7 @@ SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin)
         reds->qxl_instances.remove(qxl); // XXX owning
         red_qxl_destroy(qxl);
     } else {
-        spice_warning("VD_INTERFACE_REMOVING unsupported");
+        spice_warning("%s interface removing is unsupported", base_interface->type);
         return -1;
     }
 
-- 
GitLab