SDL_image: GIF: reduce stack usage by dynamically allocating state.

From e52c2c88eeb8f95f2910d43c1fc42a7db2f378d0 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Sun, 14 Mar 2021 17:00:32 +0300
Subject: [PATCH] GIF: reduce stack usage by dynamically allocating state.

---
 IMG_gif.c | 58 ++++++++++++++++++++++++++++---------------------------
 1 file changed, 30 insertions(+), 28 deletions(-)

diff --git a/IMG_gif.c b/IMG_gif.c
index a3ff70d..8e20f41 100644
--- a/IMG_gif.c
+++ b/IMG_gif.c
@@ -209,14 +209,10 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
     int useGlobalColormap;
     int bitPixel;
     char version[4];
+    State_t *state = NULL;
     Image *image = NULL;
     Anim_t *anim;
     Frame_t *frames, *frame;
-    State_t state;
-
-    state.ZeroDataBlock = FALSE;
-    state.fresh = FALSE;
-    state.last_byte = 0;
 
     if (src == NULL) {
         return NULL;
@@ -243,25 +239,30 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
         RWSetMsg("bad version number, not '87a' or '89a'");
         goto done;
     }
-    state.Gif89.transparent = -1;
-    state.Gif89.delayTime = -1;
-    state.Gif89.inputFlag = -1;
-    state.Gif89.disposal = GIF_DISPOSE_NA;
+    state = (State_t *)SDL_calloc(1, sizeof(State_t));
+    if (state == NULL) {
+        SDL_OutOfMemory();
+        goto done;
+    }
+    state->Gif89.transparent = -1;
+    state->Gif89.delayTime = -1;
+    state->Gif89.inputFlag = -1;
+    state->Gif89.disposal = GIF_DISPOSE_NA;
 
     if (!ReadOK(src, buf, 7)) {
         RWSetMsg("failed to read screen descriptor");
         goto done;
     }
-    state.GifScreen.Width = LM_to_uint(buf[0], buf[1]);
-    state.GifScreen.Height = LM_to_uint(buf[2], buf[3]);
-    state.GifScreen.BitPixel = 2 << (buf[4] & 0x07);
-    state.GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
-    state.GifScreen.Background = buf[5];
-    state.GifScreen.AspectRatio = buf[6];
+    state->GifScreen.Width = LM_to_uint(buf[0], buf[1]);
+    state->GifScreen.Height = LM_to_uint(buf[2], buf[3]);
+    state->GifScreen.BitPixel = 2 << (buf[4] & 0x07);
+    state->GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
+    state->GifScreen.Background = buf[5];
+    state->GifScreen.AspectRatio = buf[6];
 
     if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
-        if (ReadColorMap(src, state.GifScreen.BitPixel,
-                         state.GifScreen.ColorMap, &state.GifScreen.GrayScale)) {
+        if (ReadColorMap(src, state->GifScreen.BitPixel,
+                         state->GifScreen.ColorMap, &state->GifScreen.GrayScale)) {
             RWSetMsg("error reading global colormap");
             goto done;
         }
@@ -279,7 +280,7 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
                 RWSetMsg("EOF / read error on extention function code");
                 goto done;
             }
-            DoExtension(src, c, &state);
+            DoExtension(src, c, state);
             continue;
         }
         if (c != ',') {     /* Not a valid start character */
@@ -303,18 +304,18 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
                       LM_to_uint(buf[6], buf[7]),
                       bitPixel, localColorMap, grayScale,
                       BitSet(buf[8], INTERLACE),
-                      0, &state);
+                      0, state);
         } else {
             image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
                       LM_to_uint(buf[6], buf[7]),
-                      state.GifScreen.BitPixel, state.GifScreen.ColorMap,
-                      state.GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
-                      0, &state);
+                      state->GifScreen.BitPixel, state->GifScreen.ColorMap,
+                      state->GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
+                      0, state);
         }
 
         if (image) {
-            if (state.Gif89.transparent >= 0) {
-                SDL_SetColorKey(image, SDL_TRUE, state.Gif89.transparent);
+            if (state->Gif89.transparent >= 0) {
+                SDL_SetColorKey(image, SDL_TRUE, state->Gif89.transparent);
             }
 
             frames = (Frame_t *)SDL_realloc(anim->frames, (anim->count + 1) * sizeof(*anim->frames));
@@ -329,11 +330,11 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
             frame->image = image;
             frame->x = LM_to_uint(buf[0], buf[1]);
             frame->y = LM_to_uint(buf[2], buf[3]);
-            frame->disposal = state.Gif89.disposal;
-            if (state.Gif89.delayTime < 2) {
+            frame->disposal = state->Gif89.disposal;
+            if (state->Gif89.delayTime < 2) {
                 frame->delay = 100; /* Default animation delay, matching browsers and Qt */
             } else {
-                frame->delay = state.Gif89.delayTime * 10;
+                frame->delay = state->Gif89.delayTime * 10;
             }
 
             if (!load_anim) {
@@ -357,8 +358,9 @@ IMG_LoadGIF_RW_Internal(SDL_RWops *src, SDL_bool load_anim)
     if (anim->count == 0) {
         SDL_free(anim->frames);
         SDL_free(anim);
-        return NULL;
+        anim = NULL;
     }
+    SDL_free(state);
     return anim;
 }