SDL: audio: Enumerating audio devices will skip zombie devices still in the hash.

From eb04219efeb328c5e14e18d3e868bcb28a7bd346 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 20 Jun 2025 17:36:51 -0400
Subject: [PATCH] audio: Enumerating audio devices will skip zombie devices
 still in the hash.

---
 src/audio/SDL_audio.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index b86fc6bb351cb..90d9f9bba6321 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -1415,6 +1415,7 @@ static int SDLCALL RecordingAudioThread(void *devicep)  // thread entry point
 typedef struct CountAudioDevicesData
 {
     int devs_seen;
+    int devs_skipped;
     const int num_devices;
     SDL_AudioDeviceID *result;
     const bool recording;
@@ -1430,7 +1431,13 @@ static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table
     const bool isphysical = !!(devid & (1<<1));
     if (isphysical && (devid_recording == data->recording)) {
         SDL_assert(data->devs_seen < data->num_devices);
-        data->result[data->devs_seen++] = devid;
+        SDL_AudioDevice *device = (SDL_AudioDevice *) value;  // this is normally risky, but we hold the device_hash_lock here.
+        const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
+        if (zombie) {
+            data->devs_skipped++;
+        } else {
+            data->result[data->devs_seen++] = devid;
+        }
     }
     return true;  // keep iterating.
 }
@@ -1446,10 +1453,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
             num_devices = SDL_GetAtomicInt(recording ? &current_audio.recording_device_count : &current_audio.playback_device_count);
             result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
             if (result) {
-                CountAudioDevicesData data = { 0, num_devices, result, recording };
+                CountAudioDevicesData data = { 0, 0, num_devices, result, recording };
                 SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
-                SDL_assert(data.devs_seen == num_devices);
-                result[data.devs_seen] = 0;  // null-terminated.
+                SDL_assert((data.devs_seen + data.devs_skipped) == num_devices);
+                num_devices = data.devs_seen;  // might be less if we skipped any.
+                result[num_devices] = 0;  // null-terminated.
             }
         }
         SDL_UnlockRWLock(current_audio.device_hash_lock);