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.
This commit is contained in:
Po Lu 2023-10-04 16:33:05 +08:00
parent fbfdd1e0e3
commit bb417daa70
5 changed files with 60 additions and 21 deletions

View file

@ -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,

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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;
}