SDL_mixer: Mix_AllocateChannels realloc fix (#620) (fa989)

From fa989527060aed936299164ea861ea8ccdde4900 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zana=20Dom=C3=A1n?=
 <88244790+zanadoman@users.noreply.github.com>
Date: Thu, 4 Jul 2024 16:51:47 +0200
Subject: [PATCH] Mix_AllocateChannels realloc fix (#620)

(cherry picked from commit 2c28b9d757ce9e53d3f4ce99a016f6b4bf4c5dee)
(cherry picked from commit 0c48918b0b5ff0e82a964f36b5ad7a91e599680a)
---
 src/mixer.c | 57 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/src/mixer.c b/src/mixer.c
index 53381383d..52610d69d 100644
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -561,6 +561,8 @@ void Mix_PauseAudio(int pause_on)
  */
 int Mix_AllocateChannels(int numchans)
 {
+    struct _Mix_Channel *mix_channel_tmp;
+
     if (numchans<0 || numchans==num_channels)
         return num_channels;
 
@@ -573,27 +575,42 @@ int Mix_AllocateChannels(int numchans)
         }
     }
     Mix_LockAudio();
-    mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
-    if (numchans > num_channels) {
-        /* Initialize the new channels */
-        int i;
-        for (i = num_channels; i < numchans; i++) {
-            mix_channel[i].chunk = NULL;
-            mix_channel[i].playing = 0;
-            mix_channel[i].looping = 0;
-            mix_channel[i].volume = MIX_MAX_VOLUME;
-            mix_channel[i].fade_volume = MIX_MAX_VOLUME;
-            mix_channel[i].fade_volume_reset = MIX_MAX_VOLUME;
-            mix_channel[i].fading = MIX_NO_FADING;
-            mix_channel[i].tag = -1;
-            mix_channel[i].expire = 0;
-            mix_channel[i].effects = NULL;
-            mix_channel[i].paused = 0;
-        }
-    }
-    num_channels = numchans;
+    /* Allocate channels into temporary pointer */
+    if (numchans) {
+        mix_channel_tmp = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
+    } else {
+        /* Handle 0 numchans */
+        SDL_free(mix_channel);
+        mix_channel_tmp = NULL;
+    }
+    /* Check the allocation */
+    if (mix_channel_tmp || !numchans) {
+        /* Apply the temporary pointer on success */
+        mix_channel = mix_channel_tmp;
+        if (numchans > num_channels) {
+            /* Initialize the new channels */
+            int i;
+            for (i = num_channels; i < numchans; i++) {
+                mix_channel[i].chunk = NULL;
+                mix_channel[i].playing = 0;
+                mix_channel[i].looping = 0;
+                mix_channel[i].volume = MIX_MAX_VOLUME;
+                mix_channel[i].fade_volume = MIX_MAX_VOLUME;
+                mix_channel[i].fade_volume_reset = MIX_MAX_VOLUME;
+                mix_channel[i].fading = MIX_NO_FADING;
+                mix_channel[i].tag = -1;
+                mix_channel[i].expire = 0;
+                mix_channel[i].effects = NULL;
+                mix_channel[i].paused = 0;
+            }
+        }
+        num_channels = numchans;
+    } else {
+        /* On error mix_channel remains intact */
+        Mix_SetError("Channel allocation failed");
+    }
     Mix_UnlockAudio();
-    return num_channels;
+    return num_channels; /* If the return value equals numchans the allocation was successful */
 }
 
 /* Return the actual mixer parameters */