@samitouri / QOSamiQemu / commits / 8dc8449a67

hw/display/virtio-gpu: Avoid leaking migration blocker

virtio_gpu_base_device_realize() leaks a migration blocker if a check of the output list fails after adding one. Perform the check before adding a migration blocker to avoid the leak. This also simplifies the code by merging two loops. Fixes: d3a4969dc5ac ("Support per-head resolutions with virtio-gpu") Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260725-virgl-v1-1-58bb51e60da5@rsg.ci.i.u-tokyo.ac.jp>

Akihiko Odaki committed Jul 25, 2026 at 16:14 UTC 8dc8449a678f56ea0746e1c002f3c671ef9c456d
1 file changed +16 -21
hw/display/virtio-gpu-base.c
+16 -21
@@ -195,6 +195,11 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
195 return false;
196 }
197
198 + g->enabled_output_bitmask = 1;
199 +
200 + g->req_state[0].width = g->conf.xres;
201 + g->req_state[0].height = g->conf.yres;
202 +
203 for (output_idx = 0, node = g->conf.outputs;
204 node; output_idx++, node = node->next) {
205 if (output_idx == g->conf.max_outputs) {
@@ -207,6 +212,17 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
212 node->value->name, EDID_NAME_MAX_LENGTH);
213 return false;
214 }
215 + if (node->value->has_xres != node->value->has_yres) {
216 + error_setg(errp,
217 + "must set both outputs[%zd].xres and outputs[%zd].yres",
218 + output_idx, output_idx);
219 + return false;
220 + }
221 + if (node->value->has_xres && node->value->has_yres) {
222 + g->enabled_output_bitmask |= (1 << output_idx);
223 + g->req_state[output_idx].width = node->value->xres;
224 + g->req_state[output_idx].height = node->value->yres;
225 + }
226 }
227
228 if (virtio_gpu_virgl_enabled(g->conf)) {
@@ -229,27 +245,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
245 virtio_add_queue(vdev, 16, cursor_cb);
246 }
247
232 - g->enabled_output_bitmask = 1;
233 -
234 - g->req_state[0].width = g->conf.xres;
235 - g->req_state[0].height = g->conf.yres;
236 -
237 - for (output_idx = 0, node = g->conf.outputs;
238 - node && output_idx < g->conf.max_outputs;
239 - output_idx++, node = node->next) {
240 - if (node->value->has_xres != node->value->has_yres) {
241 - error_setg(errp,
242 - "must set both outputs[%zd].xres and outputs[%zd].yres",
243 - output_idx, output_idx);
244 - return false;
245 - }
246 - if (node->value->has_xres && node->value->has_yres) {
247 - g->enabled_output_bitmask |= (1 << output_idx);
248 - g->req_state[output_idx].width = node->value->xres;
249 - g->req_state[output_idx].height = node->value->yres;
250 - }
251 - }
252 -
248 g->hw_ops = &virtio_gpu_ops;
249 for (i = 0; i < g->conf.max_outputs; i++) {
250 g->scanout[i].con =