Explorar o código

android: Better parsing of command line arguments.

Reference Issue #14510.
Ryan C. Gordon hai 3 semanas
pai
achega
9b348ef6e8
Modificáronse 1 ficheiros con 43 adicións e 32 borrados
  1. 43 32
      src/core/android/SDL_android.c

+ 43 - 32
src/core/android/SDL_android.c

@@ -768,9 +768,6 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
     checkJNIReady();
 }
 
-// SDL main function prototype
-typedef int (*SDL_main_func)(int argc, char *argv[]);
-
 static int run_count = 0;
 static bool allow_recreate_activity;
 static bool allow_recreate_activity_set;
@@ -840,47 +837,61 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
         function_name = (*env)->GetStringUTFChars(env, function, NULL);
         SDL_main = (SDL_main_func)dlsym(library_handle, function_name);
         if (SDL_main) {
-            int i;
-            int argc;
-            int len;
-            char **argv;
-            bool isstack;
-
-            // Prepare the arguments.
-            len = (*env)->GetArrayLength(env, array);
-            argv = SDL_small_alloc(char *, 1 + len + 1, &isstack); // !!! FIXME: check for NULL
-            argc = 0;
-            /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
-               https://github.com/love2d/love-android/issues/24
-             */
-            argv[argc++] = SDL_strdup("app_process");
-            for (i = 0; i < len; ++i) {
-                char *arg = NULL;
+            // Use the name "app_process" for argv[0] so PHYSFS_platformCalcBaseDir() works.
+            //   https://github.com/love2d/love-android/issues/24
+            // (note that PhysicsFS hasn't used argv on Android in a long time, but we'll keep this for compat at least for SDL3's lifetime.  --ryan.)
+            const char *argv0 = "app_process";
+            const int len = (*env)->GetArrayLength(env, array);  // argv elements, not counting argv[0].
+
+            size_t total_alloc_len = (SDL_strlen(argv0) + 1) + ((len + 2) * sizeof (char *));  // len+2 to allocate an array that also holds argv0 and a NULL terminator.
+            for (int i = 0; i < len; ++i) {
+                total_alloc_len++;  // null terminator.
                 jstring string = (*env)->GetObjectArrayElement(env, array, i);
                 if (string) {
                     const char *utf = (*env)->GetStringUTFChars(env, string, 0);
                     if (utf) {
-                        arg = SDL_strdup(utf);
+                        total_alloc_len += SDL_strlen(utf) + 1;
                         (*env)->ReleaseStringUTFChars(env, string, utf);
                     }
                     (*env)->DeleteLocalRef(env, string);
                 }
-                if (arg == NULL) {
-                    arg = SDL_strdup("");
-                }
-                argv[argc++] = arg;
             }
-            argv[argc] = NULL;
 
-            // Run the application.
-            status = SDL_main(argc, argv);
+            void *args = malloc(total_alloc_len);  // This should NOT be SDL_malloc()
+            if (!args) { // uhoh.
+                __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Out of memory parsing command line!");
+            } else {
+                size_t remain = total_alloc_len - (sizeof (char *) * (len + 2));
+                int argc = 0;
+                char **argv = (char **) args;
+                char *ptr = (char *) &argv[len + 2];
+                size_t cpy = SDL_strlcpy(ptr, argv0, remain) + 1;
+                argv[argc++] = ptr;
+                SDL_assert(cpy <= remain); remain -= cpy; ptr += cpy;
+                for (int i = 0; i < len; ++i) {
+                    jstring string = (*env)->GetObjectArrayElement(env, array, i);
+                    const char *utf = string ? (*env)->GetStringUTFChars(env, string, 0) : NULL;
+                    cpy = SDL_strlcpy(ptr, utf ? utf : "", remain) + 1;
+                    if (cpy < remain) {
+                        argv[argc++] = ptr;
+                        remain -= cpy;
+                        ptr += cpy;
+                    }
+                    if (utf) {
+                        (*env)->ReleaseStringUTFChars(env, string, utf);
+                    }
+                    if (string) {
+                        (*env)->DeleteLocalRef(env, string);
+                    }
+                }
+                argv[argc] = NULL;
 
-            // Release the arguments.
-            for (i = 0; i < argc; ++i) {
-                SDL_free(argv[i]);
-            }
-            SDL_small_free(argv, isstack);
+                // Run the application.
+                status = SDL_RunApp(argc, argv, SDL_main, NULL);
 
+                // Release the arguments.
+                free(args);  // This should NOT be SDL_free()
+            }
         } else {
             __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
         }