sdl2-compat: Fixed memory leak if SDL_RWFromMem() is cleaned up with SDL_FreeRW()

From e5df36b0d24a02372c5d1ea5bfb7fff906660eb1 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 2 Feb 2025 16:16:36 -0800
Subject: [PATCH] Fixed memory leak if SDL_RWFromMem() is cleaned up with
 SDL_FreeRW()

---
 src/sdl2_compat.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 08e5b53..0175ef7 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -2279,12 +2279,6 @@ SDL_AllocRW(void)
     return rwops2;
 }
 
-SDL_DECLSPEC void SDLCALL
-SDL_FreeRW(SDL2_RWops *rwops2)
-{
-    SDL3_free(rwops2);
-}
-
 static Sint64 SDLCALL
 RWops3to2_size(SDL2_RWops *rwops2)
 {
@@ -2320,7 +2314,13 @@ RWops3to2_write(SDL2_RWops *rwops2, const void *ptr, size_t size, size_t maxnum)
 static int SDLCALL
 RWops3to2_close(SDL2_RWops *rwops2)
 {
-    const int retval = SDL3_CloseIO(rwops2->hidden.sdl3.iostrm) ? 0 : -1;
+    int retval = 0;
+    if (rwops2->hidden.sdl3.iostrm) {
+        if (!SDL3_CloseIO(rwops2->hidden.sdl3.iostrm)) {
+            retval = -1;
+        }
+        rwops2->hidden.sdl3.iostrm = NULL;
+    }
     SDL_FreeRW(rwops2);
     return retval;
 }
@@ -2348,6 +2348,17 @@ RWops3to2(SDL_IOStream *iostrm3, Uint32 type)
     return rwops2;
 }
 
+SDL_DECLSPEC void SDLCALL
+SDL_FreeRW(SDL2_RWops *rwops2)
+{
+    if (rwops2->close == RWops3to2_close &&
+        rwops2->hidden.sdl3.iostrm) {
+        SDL3_CloseIO(rwops2->hidden.sdl3.iostrm);
+        rwops2->hidden.sdl3.iostrm = NULL;
+    }
+    SDL3_free(rwops2);
+}
+
 SDL_DECLSPEC SDL2_RWops *SDLCALL
 SDL_RWFromFile(const char *file, const char *mode)
 {