Commit ec04110d8ed6a034a8190d4d970788fb81c6234d

Ryan C. Gordon 2019-10-14T12:41:06

dynapi: Deal with failure cases better, other fixes. Fixes Bugzilla #4803.

diff --git a/src/SDL.c b/src/SDL.c
index 6e80178..37423d4 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -45,6 +45,33 @@ extern int SDL_HelperWindowDestroy(void);
 #endif
 
 
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
+SDL_NORETURN void SDL_ExitProcess(const int exitcode)
+{
+#ifdef __WIN32__
+    /* "if you do not know the state of all threads in your process, it is
+       better to call TerminateProcess than ExitProcess"
+       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
+    TerminateProcess(GetCurrentProcess(), exitcode);
+    /* MingW doesn't have TerminateProcess marked as noreturn, so add an
+       ExitProcess here that will never be reached but make MingW happy. */
+    ExitProcess(exitcode);
+#elif defined(__EMSCRIPTEN__)
+    emscripten_cancel_main_loop();  /* this should "kill" the app. */
+    emscripten_force_exit(exitcode);  /* this should "kill" the app. */
+    exit(exitcode);
+#elif defined(__HAIKU__)  /* Haiku has _Exit, but it's not marked noreturn. */
+    _exit(exitcode);
+#elif defined(HAVE__EXIT) /* Upper case _Exit() */
+    _Exit(exitcode);
+#else
+    _exit(exitcode);
+#endif
+}
+
+
 /* The initialized subsystems */
 #ifdef SDL_MAIN_NEEDED
 static SDL_bool SDL_MainIsReady = SDL_FALSE;
diff --git a/src/SDL_assert.c b/src/SDL_assert.c
index 7ded637..ea97157 100644
--- a/src/SDL_assert.c
+++ b/src/SDL_assert.c
@@ -120,32 +120,14 @@ static void SDL_GenerateAssertionReport(void)
 }
 
 
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
 #if defined(__WATCOMC__)
-static void SDL_ExitProcess (int);
+void SDL_ExitProcess(const int exitcode);
 #pragma aux SDL_ExitProcess aborts;
 #endif
-static SDL_NORETURN void SDL_ExitProcess(int exitcode)
-{
-#ifdef __WIN32__
-    /* "if you do not know the state of all threads in your process, it is
-       better to call TerminateProcess than ExitProcess"
-       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
-    TerminateProcess(GetCurrentProcess(), exitcode);
-    /* MingW doesn't have TerminateProcess marked as noreturn, so add an
-       ExitProcess here that will never be reached but make MingW happy. */
-    ExitProcess(exitcode);
-#elif defined(__EMSCRIPTEN__)
-    emscripten_cancel_main_loop();  /* this should "kill" the app. */
-    emscripten_force_exit(exitcode);  /* this should "kill" the app. */
-    exit(exitcode);
-#elif defined(__HAIKU__)  /* Haiku has _Exit, but it's not marked noreturn. */
-    _exit(exitcode);
-#elif defined(HAVE__EXIT) /* Upper case _Exit() */
-    _Exit(exitcode);
-#else
-    _exit(exitcode);
-#endif
-}
+SDL_NORETURN void SDL_ExitProcess(const int exitcode);
 
 
 #if defined(__WATCOMC__)
diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index b5497b2..23be8aa 100644
--- a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -264,29 +264,58 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
 #endif
 
 
+static void dynapi_warn(const char *msg)
+{
+    const char *caption = "SDL Dynamic API Failure!";
+    /* SDL_ShowSimpleMessageBox() is a too heavy for here. */
+    #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
+    MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
+    #else
+    fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
+    fflush(stderr);
+    #endif
+}
+
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
+#if defined(__WATCOMC__)
+void SDL_ExitProcess(const int exitcode);
+#pragma aux SDL_ExitProcess aborts;
+#endif
+SDL_NORETURN void SDL_ExitProcess(const int exitcode);
+
+
 static void
 SDL_InitDynamicAPILocked(void)
 {
     const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
     SDL_DYNAPI_ENTRYFN entry = NULL;  /* funcs from here by default. */
+    SDL_bool use_internal = SDL_TRUE;
 
     if (libname) {
         entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
         if (!entry) {
-            /* !!! FIXME: fail to startup here instead? */
-            /* !!! FIXME: definitely warn user. */
-            /* Just fill in the function pointers from this library. */
+            dynapi_warn("Couldn't load overriding SDL library. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.");
+            /* Just fill in the function pointers from this library, later. */
         }
     }
 
-    if (!entry || (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0)) {
-        /* !!! FIXME: fail to startup here instead? */
-        /* !!! FIXME: definitely warn user. */
-        /* Just fill in the function pointers from this library. */
-        if (!entry) {
-            if (!initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
-                /* !!! FIXME: now we're screwed. Should definitely abort now. */
-            }
+    if (entry) {
+        if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
+            dynapi_warn("Couldn't override SDL library. Using a newer SDL build might help. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.");
+            /* Just fill in the function pointers from this library, later. */
+        } else {
+            use_internal = SDL_FALSE;   /* We overrode SDL! Don't use the internal version! */
+        }
+    }
+
+    /* Just fill in the function pointers from this library. */
+    if (use_internal) {
+        if (initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
+            /* Now we're screwed. Should definitely abort now. */
+            dynapi_warn("Failed to initialize internal SDL dynapi. As this would otherwise crash, we have to abort now.");
+            SDL_ExitProcess(86);
         }
     }