sdl2-compat: init: Don't call into SDL3 _at all_ during dllinit().

From 1eaad089fb793f96aaae0b38bdb20a80ed467ac4 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 5 Feb 2025 23:24:31 -0500
Subject: [PATCH] init: Don't call into SDL3 _at all_ during dllinit().

This uses platform-specific code for some tasks (get/set environment, logging,
etc), implements some simple things like strlen, and moves
SDL2Compat_InitOnStartup to SDL_InitSubSystem and wraps it in an SDL_InitState.

This removes some questions of SDL3's intialization status during these early
moments and, more importantly, makes sure we don't call into SDL_malloc before
the app has a chance to set their own allocators.

Reference Issue #309.
---
 src/dynapi/SDL_dynapi.c |  11 +-
 src/sdl2_compat.c       | 294 ++++++++++++++++++++++++++++++++--------
 src/sdl2_compat_objc.m  |  13 ++
 src/sdl3_syms.h         |   3 +
 4 files changed, 262 insertions(+), 59 deletions(-)

diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index 1e0c732..3070cdf 100644
--- a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -447,7 +447,16 @@ DynApiExitProcess(int exitcode)
 
 static void SDL_InitDynamicAPILocked(void)
 {
-    const char *libname = SDL_getenv_REAL(SDL_DYNAMIC_API_ENVVAR);
+    /* this can't use SDL_getenv_REAL, because the SDL3 version behind the scenes allocates memory before the app can set their allocator */
+#if (defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
+    /* We've always used LoadLibraryA for this, so this has never worked with Unicode paths on Windows. Sorry. */
+    char envbuf[512];  /* overflows will just report as environment variable being unset, but LoadLibraryA has a MAX_PATH of 260 anyhow, apparently. */
+    const DWORD rc = GetEnvironmentVariableA(SDL_DYNAMIC_API_ENVVAR, envbuf, (DWORD) sizeof (envbuf));
+    const char *libname = ((rc != 0) && (rc < sizeof (envbuf))) ? envbuf : NULL;
+#else
+    const char *libname = getenv(SDL_DYNAMIC_API_ENVVAR);
+#endif
+
     SDL_DYNAPI_ENTRYFN entry = NULL; /* funcs from here by default. */
     bool use_internal = true;
 
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 56fa1ee..8d86789 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -244,6 +244,82 @@ SDL2COMPAT_itoa(char *dst, int val)
     } while (ptr > dst);
 }
 
+/* you can use SDL3_strlen once we're past startup. */
+static int SDL2Compat_strlen(const char *str)
+{
+    int retval = 0;
+    while (str[retval]) {
+        retval++;
+    }
+    return retval;
+}
+
+/* you can use SDL3_strcmp once we're past startup. */
+static bool SDL2Compat_strequal(const char *a, const char *b)
+{
+    while (true) {
+        const char cha = *a;
+        if (cha != *b) {
+            return false;
+        } else if (!cha) {
+            break;
+        }
+        a++;
+        b++;
+    }
+    return true;
+}
+
+/* log a string using platform-specific code for before SDL3 is fully available. */
+static void SDL2Compat_LogAtStartup(const char *str)
+{
+    #ifdef SDL_PLATFORM_WINDOWS
+    OutputDebugStringA(str);
+    #elif defined(SDL_PLATFORM_ANDROID)
+    __android_log_write(ANDROID_LOG_INFO, "sdl2-compat", str);
+    #elif defined(SDL_PLATFORM_APPLE)
+    extern void SDL2Compat_NSLog(const char *prefix, const char *text);
+    SDL2Compat_NSLog(NULL, str);
+    #else
+    fputs(str, stderr);
+    fputs("\n", stderr);
+    #endif
+}
+
+/* this talks right to the OS environment table. Don't use SDL3_setenv at startup. */
+static void SDL2Compat_SetEnvAtStartup(const char *name, const char *value)
+{
+    #ifdef SDL_PLATFORM_WINDOWS
+    SetEnvironmentVariableA(name, value);
+    #else  /* we might need other platforms, or a simple `return;` for platforms without an environment table. */
+    if (value) {
+        setenv(name, value, 1);
+    } else {
+        unsetenv(name);
+    }
+    #endif
+}
+
+/* this talks right to the OS environment table. Don't use SDL3_getenv at startup. */
+static const char *SDL2Compat_GetEnvAtStartup(const char *name)
+{
+    #ifdef SDL_PLATFORM_WINDOWS
+    static char buf[256];  /* overflows will just report as environment variable being unset. But most of our environment vars don't come through here. */
+    const DWORD rc = GetEnvironmentVariableA(name, buf, (DWORD) sizeof (buf));
+    return ((rc != 0) && (rc < sizeof (buf))) ? buf : NULL;
+    #else  /* we might need other platforms, or a simple `return NULL;` for platforms without an environment table. */
+    return getenv(name);
+    #endif
+}
+
+
+/* this can't call into SDL3_getenv because things aren't set up yet, so try for platform-specific getenv checks. */
+static bool SDL2Compat_CheckDebugLogging(void)
+{
+    const char *value = SDL2Compat_GetEnvAtStartup("SDL2COMPAT_DEBUG_LOGGING");
+    return (value != NULL) && SDL2Compat_strequal(value, "1");
+}
+
 
 /* Obviously we can't use SDL_LoadObject() to load SDL3.  :)  */
 /* FIXME: Updated library names after https://github.com/libsdl-org/SDL/issues/5626 solidifies.  */
@@ -325,9 +401,6 @@ static char loaderror[256];
 #define DIRSEP "/"
 #endif
 
-/* init stuff we want to do after SDL3 is loaded but before the app has access to it. */
-static int SDL2Compat_InitOnStartup(void);
-
 
 static void *
 LoadSDL3Symbol(const char *fn, bool *okay)
@@ -550,37 +623,52 @@ SDL_ClearHints(void)
     SDL3_ResetHints();
 }
 
+/* DO NOT USE SDL3 FUNCTIONS IN HERE! */
 static void
 SDL2Compat_ApplyQuirks(bool force_x11)
 {
     const char *exe_name = SDL2Compat_GetExeName();
-    const char *old_env;
     unsigned int i;
 
     if (WantDebugLogging) {
-        SDL3_Log("This app appears to be named '%s'", exe_name);
+        const char *lead = "sdl2-compat: This app appears to be named:";
+        char msg[256];
+        if ((SDL2Compat_strlen(lead) + SDL2Compat_strlen(exe_name) + 2) <= (int) (sizeof (msg))) {
+            char *p = msg;
+            p = SDL2COMPAT_stpcpy(p, lead);
+            p = SDL2COMPAT_stpcpy(p, " ");
+            p = SDL2COMPAT_stpcpy(p, exe_name);
+            SDL2Compat_LogAtStartup(msg);
+        } else {
+            SDL2Compat_LogAtStartup(lead);
+            SDL2Compat_LogAtStartup(exe_name);
+        }
     }
 
     /* if you change this, update also SDL2_to_SDL3_hint() */
     for (i = 0; i < SDL_arraysize(renamed_hints); ++i) {
-        old_env = SDL3_getenv(renamed_hints[i].old_hint);
+        const char *old_env = SDL2Compat_GetEnvAtStartup(renamed_hints[i].old_hint);
         if (old_env) {
-            SDL3_setenv_unsafe(renamed_hints[i].new_hint, old_env, 1);
+            SDL2Compat_SetEnvAtStartup(renamed_hints[i].new_hint, old_env);
         }
     }
 
     #ifdef __linux__
     if (force_x11) {
-        const char *videodriver_env = SDL3_getenv("SDL_VIDEODRIVER");
-        if (videodriver_env && (SDL3_strcmp(videodriver_env, "x11") != 0)) {
+        const char *videodriver_env = SDL2Compat_GetEnvAtStartup("SDL_VIDEODRIVER");
+        if (videodriver_env && !SDL2Compat_strequal(videodriver_env, "x11")) {
             if (WantDebugLogging) {
-                SDL3_Log("This app looks like it requires X11, but the SDL_VIDEODRIVER environment variable is set to \"%s\". If you have issues, try setting SDL_VIDEODRIVER=x11", videodriver_env);
+                SDL2Compat_LogAtStartup("sdl2-compat: This app looks like it requires X11, but the SDL_VIDEODRIVER environment variable is currently set to:");
+                SDL2Compat_LogAtStartup("");
+                SDL2Compat_LogAtStartup(videodriver_env);
+                SDL2Compat_LogAtStartup("");
+                SDL2Compat_LogAtStartup("If you have issues, try setting SDL_VIDEODRIVER=x11");
             }
         } else {
             if (WantDebugLogging) {
-                SDL3_Log("sdl2-compat: We are forcing this app to use X11, because it probably talks to an X server directly, outside of SDL. If possible, this app should be fixed, to be compatible with Wayland, etc.");
+                SDL2Compat_LogAtStartup("sdl2-compat: We are forcing this app to use X11, because it probably talks to an X server directly, outside of SDL. If possible, this app should be fixed, to be compatible with Wayland, etc.");
             }
-            SDL3_setenv_unsafe("SDL_VIDEO_DRIVER", "x11", 1);
+            SDL2Compat_SetEnvAtStartup("SDL_VIDEO_DRIVER", "x11");
         }
     }
     #endif
@@ -588,27 +676,62 @@ SDL2Compat_ApplyQuirks(bool force_x11)
     if (*exe_name == '\0') {
         return;
     }
+
     for (i = 0; i < SDL_arraysize(quirks); i++) {
-        if (!SDL3_strcmp(exe_name, quirks[i].exe_name)) {
-            const char *var = SDL3_getenv(quirks[i].hint_name);
+        if (SDL2Compat_strequal(exe_name, quirks[i].exe_name)) {
+            const char *var = SDL2Compat_GetEnvAtStartup(quirks[i].hint_name);
             if (!var) {
                 if (WantDebugLogging) {
-                    SDL3_Log("Applying compatibility quirk %s=\"%s\" for \"%s\"", quirks[i].hint_name, quirks[i].hint_value, exe_name);
+                    char msg[256];
+                    char *p = msg;
+                    p = SDL2COMPAT_stpcpy(p, "sdl2-compat: Applying compatibility quirk ");
+                    p = SDL2COMPAT_stpcpy(p, quirks[i].hint_name);
+                    p = SDL2COMPAT_stpcpy(p, "=\"");
+                    p = SDL2COMPAT_stpcpy(p, quirks[i].hint_value);
+                    p = SDL2COMPAT_stpcpy(p, "\".");
+                    SDL2Compat_LogAtStartup(msg);
                 }
-                SDL3_setenv_unsafe(quirks[i].hint_name, quirks[i].hint_value, 1);
+                SDL2Compat_SetEnvAtStartup(quirks[i].hint_name, quirks[i].hint_value);
             } else {
                 if (WantDebugLogging) {
-                    SDL3_Log("Not applying compatibility quirk %s=\"%s\" for \"%s\" due to environment variable override (\"%s\")\n",
-                            quirks[i].hint_name, quirks[i].hint_value, exe_name, var);
+                    char msg[256];
+                    char varbuf[32];
+                    char *p = msg;
+                    int j;
+
+                    /* copy the start of untrusted string var to a small array to prevent buffer overflows */
+                    for (j = 0; j < ((int) SDL_arraysize(varbuf)); j++) {
+                        varbuf[j] = var[j];
+                        if (var[j] == 0) {
+                            break;
+                        }
+                    }
+
+                    if (j == SDL_arraysize(varbuf)) {  /* truncate and terminate the string if necessary. */
+                        SDL2COMPAT_stpcpy(varbuf + (SDL_arraysize(varbuf) - 6), "[...]");
+                    }
+
+                    p = SDL2COMPAT_stpcpy(p, "sdl2-compat: Not applying compatibility quirk ");
+                    p = SDL2COMPAT_stpcpy(p, quirks[i].hint_name);
+                    p = SDL2COMPAT_stpcpy(p, "=\"");
+                    p = SDL2COMPAT_stpcpy(p, quirks[i].hint_value);
+                    p = SDL2COMPAT_stpcpy(p, "\" due to environment variable override (\"");
+                    p = SDL2COMPAT_stpcpy(p, varbuf);
+                    p = SDL2COMPAT_stpcpy(p, "\").");
+                    SDL2Compat_LogAtStartup(msg);
                 }
             }
         }
     }
-    if (SDL3_strcmp(exe_name, "Torchlight.bin.x86_64") == 0) {
+    if (SDL2Compat_strequal(exe_name, "Torchlight.bin.x86_64")) {
         UseSDL2PrereleaseEvents = true;
     }
 }
 
+
+/* DO NOT CALL THINGS THAT USE SDL ALLOCATORS HERE. It runs before main(), so app-supplied allocators are not set at this point.
+   This means no SDL_Log, no hint subsystem, nothing that might call SDL_SetError! In fact, favor code in this file, using
+   platform-specific #ifdefs, to calling into SDL3 at all, if you can help it. */
 static int
 LoadSDL3(void)
 {
@@ -632,6 +755,8 @@ LoadSDL3(void)
         }
         #endif
 
+        WantDebugLogging = SDL2Compat_CheckDebugLogging();
+
         okay = LoadSDL3Library();
         if (!okay) {
             SDL2COMPAT_stpcpy(loaderror, "Failed loading SDL3 library.");
@@ -639,41 +764,60 @@ LoadSDL3(void)
             #define SDL3_SYM(rc,fn,params,args,ret) SDL3_##fn = (SDL3_##fn##_t) LoadSDL3Symbol("SDL_" #fn, &okay);
             #include "sdl3_syms.h"
             if (okay) {
+                char sdl3verstr[16];
+                char sdl3reqverstr[16];
+                char sdl2compatverstr[16];
                 const int sdl3version = SDL3_GetVersion();
                 const int sdl3major = SDL_VERSIONNUM_MAJOR(sdl3version);
                 const int sdl3minor = SDL_VERSIONNUM_MINOR(sdl3version);
                 const int sdl3micro = SDL_VERSIONNUM_MICRO(sdl3version);
+                char *p;
+
+                #define SETVERSTR(str, major, minor, micro) { \
+                    char value[16]; \
+                    p = str; \
+                    SDL2COMPAT_itoa(value, major); p = SDL2COMPAT_stpcpy(p, value); *p++ = '.'; \
+                    SDL2COMPAT_itoa(value, minor); p = SDL2COMPAT_stpcpy(p, value); *p++ = '.'; \
+                    SDL2COMPAT_itoa(value, micro); p = SDL2COMPAT_stpcpy(p, value); \
+                }
 
-                okay = (sdl3version >= SDL3_REQUIRED_VER);
-                if (!okay) {
-                    char value[12];
-                    char *p = SDL2COMPAT_stpcpy(loaderror, "SDL3 ");
+                SETVERSTR(sdl3verstr, sdl3major, sdl3minor, sdl3micro);
+                SETVERSTR(sdl3reqverstr, SDL_VERSIONNUM_MAJOR(SDL3_REQUIRED_VER), SDL_VERSIONNUM_MINOR(SDL3_REQUIRED_VER), SDL_VERSIONNUM_MICRO(SDL3_REQUIRED_VER));
+                SETVERSTR(sdl2compatverstr, 2, SDL2_COMPAT_VERSION_MINOR, SDL2_COMPAT_VERSION_PATCH);
 
-                    SDL2COMPAT_itoa(value, sdl3major);
-                    p = SDL2COMPAT_stpcpy(p, value); *p++ = '.';
-                    SDL2COMPAT_itoa(value, sdl3minor);
-                    p = SDL2COMPAT_stpcpy(p, value); *p++ = '.';
-                    SDL2COMPAT_itoa(value, sdl3micro);
-                    p = SDL2COMPAT_stpcpy(p, value);
+                #undef SETVERSTR
 
-                    SDL2COMPAT_stpcpy(p, " library is too old.");
+                okay = (sdl3version >= SDL3_REQUIRED_VER);
+                if (!okay) {
+                    p = loaderror;
+                    p = SDL2COMPAT_stpcpy(p, "sdl2-compat ");
+                    p = SDL2COMPAT_stpcpy(p, sdl2compatverstr);
+                    p = SDL2COMPAT_stpcpy(p, ": SDL3 library is too old (have ");
+                    p = SDL2COMPAT_stpcpy(p, sdl3verstr);
+                    p = SDL2COMPAT_stpcpy(p, ", but need at least ");
+                    p = SDL2COMPAT_stpcpy(p, sdl3verstr);
+                    p = SDL2COMPAT_stpcpy(p, ").");
                 } else {
-                    WantDebugLogging = SDL2Compat_GetHintBoolean("SDL2COMPAT_DEBUG_LOGGING", false);
                     if (WantDebugLogging) {
+                        char debugmsg[128];  /* can't use SDL log or malloc, just write to a stack buffer and do a simple platform-specific logging. */
+
+                        p = debugmsg;
+                        p = SDL2COMPAT_stpcpy(p, "sdl2-compat ");
+                        p = SDL2COMPAT_stpcpy(p, sdl2compatverstr);
+                        p = SDL2COMPAT_stpcpy(p, ", ");
+
                         #if defined(__DATE__) && defined(__TIME__)
-                        SDL3_Log("sdl2-compat 2.%d.%d, built on " __DATE__ " at " __TIME__ ", talking to SDL3 %d.%d.%d",
-                                 SDL2_COMPAT_VERSION_MINOR, SDL2_COMPAT_VERSION_PATCH, sdl3major, sdl3minor, sdl3micro);
-                        #else
-                        SDL3_Log("sdl2-compat 2.%d.%d, talking to SDL3 %d.%d.%d",
-                                 SDL2_COMPAT_VERSION_MINOR, SDL2_COMPAT_VERSION_PATCH, sdl3major, sdl3minor, sdl3micro);
+                        p = SDL2COMPAT_stpcpy(p, "built on " __DATE__ " at " __TIME__ ", ");
                         #endif
+
+                        p = SDL2COMPAT_stpcpy(p, "talking to SDL3 ");
+                        p = SDL2COMPAT_stpcpy(p, sdl3verstr);
+
+                        SDL2Compat_LogAtStartup(debugmsg);
                     }
                     SDL2Compat_ApplyQuirks(force_x11);  /* Apply and maybe print a list of any enabled quirks. */
                 }
             }
-            if (okay) {
-                okay = SDL2Compat_InitOnStartup();
-            }
             if (!okay) {
                 UnloadSDL3();
             }
@@ -851,6 +995,37 @@ static SDL_PropertiesID timers = 0;
 
 /* Functions! */
 
+static SDL_InitState InitSDL2CompatGlobals;
+
+static void SDL2Compat_QuitInternal(void)
+{
+    if (EventWatchListMutex) {
+        SDL3_DestroyMutex(EventWatchListMutex);
+        EventWatchListMutex = NULL;
+    }
+    if (sensor_lock) {
+        SDL3_DestroyMutex(sensor_lock);
+        sensor_lock = NULL;
+    }
+    if (joystick_lock) {
+        SDL3_DestroyMutex(joystick_lock);
+        joystick_lock = NULL;
+    }
+    if (AudioDeviceLock) {
+        SDL3_DestroyMutex(AudioDeviceLock);
+        AudioDeviceLock = NULL;
+    }
+}
+
+static void SDL2Compat_Quit(void)
+{
+    if (SDL3_ShouldQuit(&InitSDL2CompatGlobals)) {
+        SDL2Compat_QuitInternal();
+        SDL3_SetInitialized(&InitSDL2CompatGlobals, false);
+    }
+}
+
+/* !!! FIXME: move this function closer to SDL_InitSubSystem */
 static void
 SDL2Compat_InitLogPrefixes(void)
 {
@@ -862,9 +1037,10 @@ SDL2Compat_InitLogPrefixes(void)
     SDL3_SetLogPriorityPrefix(SDL_LOG_PRIORITY_CRITICAL, "CRITICAL: ");
 }
 
-/* this stuff _might_ move to SDL_Init later */
-static int
-SDL2Compat_InitOnStartup(void)
+/* init stuff we want to do after SDL3 is loaded but before the app has access to it. */
+/* !!! FIXME: move this function closer to SDL_InitSubSystem */
+static bool
+SDL2Compat_InitOnStartupInternal(void)
 {
     EventWatchListMutex = SDL3_CreateMutex();
     if (!EventWatchListMutex) {
@@ -892,26 +1068,24 @@ SDL2Compat_InitOnStartup(void)
 
     SDL2Compat_InitLogPrefixes();
 
-    return 1;
+    return true;
 
 fail:
-    SDL2COMPAT_stpcpy(loaderror, "Failed to initialize sdl2-compat library.");
+    SDL2Compat_QuitInternal();
+    SDL3_SetError("Failed to initialize sdl2-compat library.");
 
-    if (EventWatchListMutex) {
-        SDL3_DestroyMutex(EventWatchListMutex);
-    }
-    if (sensor_lock) {
-        SDL3_DestroyMutex(sensor_lock);
-    }
-    if (joystick_lock) {
-        SDL3_DestroyMutex(joystick_lock);
-    }
-    if (AudioDeviceLock) {
-        SDL3_DestroyMutex(AudioDeviceLock);
-    }
-    return 0;
+    return false;
 }
 
+static bool SDL2Compat_InitOnStartup(void)
+{
+    bool retval = true;
+    if (SDL3_ShouldInit(&InitSDL2CompatGlobals)) {
+        retval = SDL2Compat_InitOnStartupInternal();
+        SDL3_SetInitialized(&InitSDL2CompatGlobals, retval);
+    }
+    return retval;
+}
 
 /* obviously we have to override this so we don't report ourselves as SDL3. */
 SDL_DECLSPEC void SDLCALL
@@ -5595,7 +5769,9 @@ SDL_InitSubSystem(Uint32 flags)
 {
     int result;
 
-    SDL2Compat_InitLogPrefixes();
+    if (!SDL2Compat_InitOnStartup()) {
+        return -1;
+    }
 
     /* Update IME UI hint */
     if (flags & SDL_INIT_VIDEO) {
@@ -5704,6 +5880,8 @@ SDL_Quit(void)
         priorities[i] = SDL3_GetLogPriority(i);
     }
 
+    SDL2Compat_Quit();
+
     SDL3_Quit();
 
     for (i = 0; i < SDL_LOG_CATEGORY_CUSTOM; i++) {
diff --git a/src/sdl2_compat_objc.m b/src/sdl2_compat_objc.m
index ac6a22d..9f6737d 100644
--- a/src/sdl2_compat_objc.m
+++ b/src/sdl2_compat_objc.m
@@ -34,6 +34,19 @@
 #define NSAlertStyleCritical NSCriticalAlertStyle
 #endif
 
+SDL2_PRIVATE void SDL2Compat_NSLog(const char *prefix, const char *text)
+{
+    @autoreleasepool {
+        NSString *nsText = [NSString stringWithUTF8String:text];
+        if (prefix && *prefix) {
+            NSString *nsPrefix = [NSString stringWithUTF8String:prefix];
+            NSLog(@"%@%@", nsPrefix, nsText);
+        } else {
+            NSLog(@"%@", nsText);
+        }
+    }
+}
+
 SDL2_PRIVATE void error_dialog(const char *errorMsg)
 {
     NSAlert *alert;
diff --git a/src/sdl3_syms.h b/src/sdl3_syms.h
index 8d20952..d271a65 100644
--- a/src/sdl3_syms.h
+++ b/src/sdl3_syms.h
@@ -612,6 +612,7 @@ SDL3_SYM(void,SetGamepadEventsEnabled,(bool a),(a),)
 SDL3_SYM(bool,SetGamepadPlayerIndex,(SDL_GameController *a, int b),(a,b),return)
 SDL3_SYM(bool,SetHint,(const char *a, const char *b),(a,b),return)
 SDL3_SYM(bool,SetHintWithPriority,(const char *a, const char *b, SDL_HintPriority c),(a,b,c),return)
+SDL3_SYM(void,SetInitialized,(SDL_InitState *a, bool b),(a,b),)
 SDL3_SYM(void,SetJoystickEventsEnabled,(bool a),(a),)
 SDL3_SYM(bool,SetJoystickPlayerIndex,(SDL_Joystick *a, int b),(a,b),return)
 SDL3_SYM(bool,SetLogPriorityPrefix,(SDL_LogPriority a, const char *b),(a,b),return)
@@ -667,6 +668,8 @@ SDL3_SYM(bool,SetWindowTitle,(SDL_Window *a, const char *b),(a,b),return)
 SDL3_SYM(bool,ShowCursor,(void),(),return)
 SDL3_SYM_PASSTHROUGH_RETCODE(bool,ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
 SDL3_SYM_PASSTHROUGH_RETCODE(bool,ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
+SDL3_SYM(bool,ShouldInit,(SDL_InitState *a),(a),return)
+SDL3_SYM(bool,ShouldQuit,(SDL_InitState *a),(a),return)
 SDL3_SYM(bool,ShowWindow,(SDL_Window *a),(a),return)
 SDL3_SYM(void,SignalCondition,(SDL_Condition *a),(a),return)
 SDL3_SYM(void,SignalSemaphore,(SDL_Semaphore *a),(a),return)