From bb417daa703b0dd8871470ce53a40b16b1ca300b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Wed, 4 Oct 2023 16:33:05 +0800 Subject: [PATCH] Correct local reference leaks * src/android.c (android_build_string): Accept a list of local references to destroy upon an allocation failure, facilitating the proper deallocation of local references in such situations. (android_browse_url): Revise for new calling convention. * src/android.h (android_build_string): Update declaration correspondingly. * src/androidmenu.c (android_menu_show, android_dialog_show): Revise for new calling convention. * src/androidselect.c (android_notifications_notify_1): Supply each successive local reference to android_build_string as notification text is being encoded. * src/androidvfs.c (android_saf_exception_check): Introduce absent va_end. --- src/android.c | 45 +++++++++++++++++++++++++++++++++++++++------ src/android.h | 2 +- src/androidmenu.c | 16 ++++++++-------- src/androidselect.c | 10 ++++++---- src/androidvfs.c | 8 ++++++-- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/android.c b/src/android.c index aa4033c676f..1424270e785 100644 --- a/src/android.c +++ b/src/android.c @@ -5593,15 +5593,20 @@ android_verify_jni_string (const char *name) } /* Given a Lisp string TEXT, return a local reference to an equivalent - Java string. */ + Java string. Each argument following TEXT should be NULL or a + local reference that will be freed if creating the string fails, + whereupon memory_full will also be signaled. */ jstring -android_build_string (Lisp_Object text) +android_build_string (Lisp_Object text, ...) { Lisp_Object encoded; jstring string; size_t nchars; jchar *characters; + va_list ap; + jobject object; + USE_SAFE_ALLOCA; /* Directly encode TEXT if it contains no non-ASCII characters, or @@ -5619,9 +5624,11 @@ android_build_string (Lisp_Object text) { string = (*android_java_env)->NewStringUTF (android_java_env, SSDATA (text)); - android_exception_check (); - SAFE_FREE (); + if ((*android_java_env)->ExceptionCheck (android_java_env)) + goto error; + + SAFE_FREE (); return string; } @@ -5640,10 +5647,36 @@ android_build_string (Lisp_Object text) string = (*android_java_env)->NewString (android_java_env, characters, nchars); - android_exception_check (); + + if ((*android_java_env)->ExceptionCheck (android_java_env)) + goto error; SAFE_FREE (); return string; + + error: + /* An exception arose while creating the string. When this + transpires, an assumption is made that the error was induced by + running out of memory. Delete each of the local references + within AP. */ + + va_start (ap, text); + + __android_log_print (ANDROID_LOG_WARN, __func__, + "Possible out of memory error. " + " The Java exception follows: "); + /* Describe exactly what went wrong. */ + (*android_java_env)->ExceptionDescribe (android_java_env); + (*android_java_env)->ExceptionClear (android_java_env); + + /* Now remove each and every local reference provided after + OBJECT. */ + + while ((object = va_arg (ap, jobject))) + ANDROID_DELETE_LOCAL_REF (object); + + va_end (ap); + memory_full (0); } /* Do the same, except TEXT is constant string data in ASCII or @@ -6154,7 +6187,7 @@ android_browse_url (Lisp_Object url, Lisp_Object send) Lisp_Object tem; const char *buffer; - string = android_build_string (url); + string = android_build_string (url, NULL); value = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env, emacs_service, diff --git a/src/android.h b/src/android.h index d4605c11ad0..28d9d25930e 100644 --- a/src/android.h +++ b/src/android.h @@ -108,7 +108,7 @@ extern void android_set_dont_focus_on_map (android_window, bool); extern void android_set_dont_accept_focus (android_window, bool); extern int android_verify_jni_string (const char *); -extern jstring android_build_string (Lisp_Object); +extern jstring android_build_string (Lisp_Object, ...); extern jstring android_build_jstring (const char *); extern void android_exception_check (void); extern void android_exception_check_1 (jobject); diff --git a/src/androidmenu.c b/src/androidmenu.c index ed26bdafa85..1f4d91b527d 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c @@ -278,7 +278,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, title_string = NULL; if (STRINGP (title) && menu_items_n_panes < 2) - title_string = android_build_string (title); + title_string = android_build_string (title, NULL); /* Push the first local frame for the context menu. */ method = menu_class.create_context_menu; @@ -370,7 +370,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, pane_name = Fsubstring (pane_name, make_fixnum (1), Qnil); /* Add the pane. */ - temp = android_build_string (pane_name); + temp = android_build_string (pane_name, NULL); android_exception_check (); (*env)->CallNonvirtualVoidMethod (env, current_context_menu, @@ -399,7 +399,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, { /* This is a submenu. Add it. */ title_string = (!NILP (item_name) - ? android_build_string (item_name) + ? android_build_string (item_name, NULL) : NULL); help_string = NULL; @@ -408,7 +408,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, if (android_get_current_api_level () >= 26 && STRINGP (help)) - help_string = android_build_string (help); + help_string = android_build_string (help, NULL); store = current_context_menu; current_context_menu @@ -443,7 +443,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, /* Add this menu item with the appropriate state. */ title_string = (!NILP (item_name) - ? android_build_string (item_name) + ? android_build_string (item_name, NULL) : NULL); help_string = NULL; @@ -452,7 +452,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, if (android_get_current_api_level () >= 26 && STRINGP (help)) - help_string = android_build_string (help); + help_string = android_build_string (help, NULL); /* Determine whether or not to display a check box. */ @@ -686,7 +686,7 @@ android_dialog_show (struct frame *f, Lisp_Object title, : android_build_jstring ("Question")); /* And the title. */ - java_title = android_build_string (title); + java_title = android_build_string (title, NULL); /* Now create the dialog. */ method = dialog_class.create_dialog; @@ -738,7 +738,7 @@ android_dialog_show (struct frame *f, Lisp_Object title, } /* Add the button. */ - temp = android_build_string (item_name); + temp = android_build_string (item_name, NULL); (*env)->CallNonvirtualVoidMethod (env, dialog, dialog_class.class, dialog_class.add_button, diff --git a/src/androidselect.c b/src/androidselect.c index cf2265d4cf4..3f025351093 100644 --- a/src/androidselect.c +++ b/src/androidselect.c @@ -613,10 +613,12 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body, (long int) (boot_time.tv_sec / 2), id); /* Encode all strings into their Java counterparts. */ - title1 = android_build_string (title); - body1 = android_build_string (body); - group1 = android_build_string (group); - identifier1 = android_build_jstring (identifier); + title1 = android_build_string (title, NULL); + body1 = android_build_string (body, title1, NULL); + group1 = android_build_string (group, body1, title1, NULL); + identifier1 + = (*android_java_env)->NewStringUTF (android_java_env, identifier); + android_exception_check_3 (title1, body1, group1); /* Create the notification. */ notification diff --git a/src/androidvfs.c b/src/androidvfs.c index 0e5bbf8a13e..94c5d35ed2c 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -3995,8 +3995,11 @@ android_saf_exception_check (int n, ...) /* First, check for an exception. */ if (!(*env)->ExceptionCheck (env)) - /* No exception has taken place. Return 0. */ - return 0; + { + /* No exception has taken place. Return 0. */ + va_end (ap); + return 0; + } /* Print the exception. */ (*env)->ExceptionDescribe (env); @@ -4045,6 +4048,7 @@ android_saf_exception_check (int n, ...) /* expression is still a local reference! */ ANDROID_DELETE_LOCAL_REF ((jobject) exception); errno = new_errno; + va_end (ap); return 1; } -- 2.39.2