diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 7623d8bae0..0bd7813e3e 100644 --- a/src/core/android/SDL_android.c +++ b/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; + // 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]. - // 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; + 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(""); + } + + 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++] = arg; + argv[argc] = NULL; + + // Run the application. + status = SDL_RunApp(argc, argv, SDL_main, NULL); + + // Release the arguments. + free(args); // This should NOT be SDL_free() } - argv[argc] = NULL; - - // Run the application. - status = SDL_main(argc, argv); - - // Release the arguments. - for (i = 0; i < argc; ++i) { - SDL_free(argv[i]); - } - SDL_small_free(argv, isstack); - } else { __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file); }