sdl2-compat: Fixed double-free if SDL RLE encodes a surface during blit

From 29e95abea7c0105d8d4172af8262d33be688cda2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 2 Feb 2025 11:21:01 -0800
Subject: [PATCH] Fixed double-free if SDL RLE encodes a surface during blit

Fixes https://github.com/libsdl-org/sdl2-compat/issues/271
---
 src/sdl2_compat.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 69df06a..3c9cd88 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -2794,6 +2794,20 @@ static SDL2_Surface *Surface3to2(SDL_Surface *surface)
     return surface2;
 }
 
+static void SynchronizeSurface3to2(SDL_Surface *surface, SDL2_Surface *surface2)
+{
+    /* Synchronize any changes made by SDL to the SDL3 surface
+     * SDL might have changed flags or freed the pixels, e.g.:
+     * https://github.com/libsdl-org/SDL/blob/be991239d9bc6df06b0ca7a9ae9dbb7251e93c12/src/video/SDL_RLEaccel.c#L1180-L1189
+     */
+    if (surface && surface->pixels != surface2->pixels) {
+        surface2->flags &= ~(surface->flags & SHARED_SURFACE_FLAGS);
+        surface2->flags |= (surface->flags & SHARED_SURFACE_FLAGS);
+        surface2->pixels = surface->pixels;
+        surface2->pitch = surface->pitch;
+    }
+}
+
 static SDL_Surface *Surface2to3(SDL2_Surface *surface)
 {
     SDL_Surface *surface3 = NULL;
@@ -3209,9 +3223,13 @@ SDL_UpperBlit(SDL2_Surface *src, const SDL_Rect *srcrect, SDL2_Surface *dst, SDL
 }
 
 SDL_DECLSPEC int SDLCALL
-SDL_LowerBlit(SDL2_Surface *src, SDL_Rect *srcrect, SDL2_Surface *dst, SDL_Rect *dstrect)
+SDL_LowerBlit(SDL2_Surface *src2, SDL_Rect *srcrect, SDL2_Surface *dst2, SDL_Rect *dstrect)
 {
-    return SDL3_BlitSurfaceUnchecked(Surface2to3(src), srcrect, Surface2to3(dst), dstrect) ? 0 : -1;
+    SDL_Surface *src = Surface2to3(src2);
+    SDL_Surface *dst = Surface2to3(dst2);
+    int result = SDL3_BlitSurfaceUnchecked(src, srcrect, dst, dstrect) ? 0 : -1;
+    SynchronizeSurface3to2(src, src2);
+    return result;
 }
 
 SDL_DECLSPEC int SDLCALL
@@ -3375,9 +3393,13 @@ SDL_UpperBlitScaled(SDL2_Surface *src, const SDL_Rect *srcrect, SDL2_Surface *ds
 }
 
 SDL_DECLSPEC int SDLCALL
-SDL_LowerBlitScaled(SDL2_Surface *src, SDL_Rect *srcrect, SDL2_Surface *dst, SDL_Rect *dstrect)
+SDL_LowerBlitScaled(SDL2_Surface *src2, SDL_Rect *srcrect, SDL2_Surface *dst2, SDL_Rect *dstrect)
 {
-    return SDL3_BlitSurfaceUncheckedScaled(Surface2to3(src), srcrect, Surface2to3(dst), dstrect, SDL_SCALEMODE_NEAREST) ? 0 : -1;
+    SDL_Surface *src = Surface2to3(src2);
+    SDL_Surface *dst = Surface2to3(dst2);
+    int result = SDL3_BlitSurfaceUncheckedScaled(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST) ? 0 : -1;
+    SynchronizeSurface3to2(src, src2);
+    return result;
 }
 
 SDL_DECLSPEC int SDLCALL