SDL: messagebox: Copy title and message up front, to protect SDL_GetError() strings.

From d0d1414836e340361c50db1d9f8d9e0672b187e1 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 16 Dec 2024 18:02:37 -0500
Subject: [PATCH] messagebox: Copy title and message up front, to protect
 SDL_GetError() strings.

It's possible (likely!) someone could just pass a pointer returned by
SDL_GetError for one of these strings, but the message box code has to do a
ton of complicated stuff that might _also_ call SDL_SetError, so you could
end up with the string having different contents by the time you display it.

Just make a copy of the strings unconditionally at the start, so they're safe
no matter where they came from.

Fixes #10932.
---
 src/video/SDL_video.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index b62d5c53a091b..9760a4426a1e6 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -5455,6 +5455,30 @@ bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
         return SDL_SetError("Invalid number of buttons");
     }
 
+    // in case either the title or message was a pointer from SDL_GetError(), make a copy
+    // now, as we'll likely overwrite error state in here.
+    bool titleisstack = false, msgisstack = false;
+    char *titlecpy = NULL;
+    char *msgcpy = NULL;
+    if (messageboxdata->title) {
+        const size_t slen = SDL_strlen(messageboxdata->title) + 1;
+        titlecpy = SDL_small_alloc(char, slen, &titleisstack);
+        if (!titlecpy) {
+            return false;
+        }
+        SDL_strlcpy(titlecpy, messageboxdata->title, slen);
+    }
+
+    if (messageboxdata->message) {
+        const size_t slen = SDL_strlen(messageboxdata->message) + 1;
+        msgcpy = SDL_small_alloc(char, slen, &msgisstack);
+        if (!msgcpy) {
+            SDL_small_free(titlecpy, titleisstack);
+            return false;
+        }
+        SDL_strlcpy(msgcpy, messageboxdata->message, slen);
+    }
+
     (void)SDL_AtomicIncRef(&SDL_messagebox_count);
 
     current_window = SDL_GetKeyboardFocus();
@@ -5469,9 +5493,11 @@ bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
     }
 
     SDL_memcpy(&mbdata, messageboxdata, sizeof(*messageboxdata));
+    mbdata.title = titlecpy;
     if (!mbdata.title) {
         mbdata.title = "";
     }
+    mbdata.message = msgcpy;
     if (!mbdata.message) {
         mbdata.message = "";
     }
@@ -5534,6 +5560,9 @@ bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
     SDL_UpdateRelativeMouseMode();
     SDL_UpdateMouseCapture(false);
 
+    SDL_small_free(msgcpy, msgisstack);
+    SDL_small_free(titlecpy, titleisstack);
+
     return result;
 }