From f7856181849939ecb096dd1d0068b674fe2c69ff Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 16 Nov 2023 09:20:46 +0200 Subject: virtio-sound: add realize() error cleanup path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU crashes on exit when a virtio-sound device has failed to realise. Its vmstate field was not cleaned up properly with qemu_del_vm_change_state_handler(). This patch changes the realize() order as 1. Validate the given configuration values (no resources allocated by us either on success or failure) 2. Try AUD_register_card() and return on failure (no resources allocated by us on failure) 3. Initialize vmstate, virtio device, heap allocations and stream parameters at once. If error occurs, goto error_cleanup label which calls virtio_snd_unrealize(). This cleans up all resources made in steps 1-3. Reported-by: Volker Rümelin Fixes: 2880e676c000 ("Add virtio-sound device stub") Signed-off-by: Manos Pitsidianakis Message-Id: <20231116072046.4002957-1-manos.pitsidianakis@linaro.org> Reviewed-by: Philippe Mathieu-Daudé --- hw/audio/virtio-snd.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'hw/audio') diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c index 83e9785..3c9f94e 100644 --- a/hw/audio/virtio-snd.c +++ b/hw/audio/virtio-snd.c @@ -36,6 +36,7 @@ static void virtio_snd_pcm_out_cb(void *data, int available); static void virtio_snd_process_cmdq(VirtIOSound *s); static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream); static void virtio_snd_pcm_in_cb(void *data, int available); +static void virtio_snd_unrealize(DeviceState *dev); static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8) | BIT(VIRTIO_SND_PCM_FMT_U8) @@ -1065,23 +1066,9 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp) virtio_snd_pcm_set_params default_params = { 0 }; uint32_t status; - vsnd->pcm = NULL; - vsnd->vmstate = - qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); - trace_virtio_snd_realize(vsnd); - vsnd->pcm = g_new0(VirtIOSoundPCM, 1); - vsnd->pcm->snd = vsnd; - vsnd->pcm->streams = - g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams); - vsnd->pcm->pcm_params = - g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams); - - virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); - virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); - - /* set number of jacks and streams */ + /* check number of jacks and streams */ if (vsnd->snd_conf.jacks > 8) { error_setg(errp, "Invalid number of jacks: %"PRIu32, @@ -1106,6 +1093,19 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp) return; } + vsnd->vmstate = + qemu_add_vm_change_state_handler(virtio_snd_vm_state_change, vsnd); + + vsnd->pcm = g_new0(VirtIOSoundPCM, 1); + vsnd->pcm->snd = vsnd; + vsnd->pcm->streams = + g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams); + vsnd->pcm->pcm_params = + g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams); + + virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config)); + virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1); + /* set default params for all streams */ default_params.features = 0; default_params.buffer_bytes = cpu_to_le32(8192); @@ -1130,16 +1130,21 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp) error_setg(errp, "Can't initialize stream params, device responded with %s.", print_code(status)); - return; + goto error_cleanup; } status = virtio_snd_pcm_prepare(vsnd, i); if (status != cpu_to_le32(VIRTIO_SND_S_OK)) { error_setg(errp, "Can't prepare streams, device responded with %s.", print_code(status)); - return; + goto error_cleanup; } } + + return; + +error_cleanup: + virtio_snd_unrealize(dev); } static inline void return_tx_buffer(VirtIOSoundPCMStream *stream, -- cgit v1.1