diff --git a/NEWS b/NEWS index 83965ccf..52a106fc 100644 --- a/NEWS +++ b/NEWS @@ -105,6 +105,20 @@ have already been considered. (mostly reverted) ////////////////////////////////////////////////////////////////////// +ELinks 0.12pre5.GIT now: +------------------------ + +To be released as 0.12pre6 or 0.12rc1. + +Bugs that should be removed from NEWS before the 0.12.0 release: + +* critical bug 943: Don't let user JavaScripts call any methods of + ``elinks.action'' in tabs that do not have the focus. If a tab was + closed with ``elinks.action.tab_close'' while it had pop-up windows, + ELinks could crash; as a precaution, don't allow other actions + either. ELinks 0.12pre1 was the first release that supported + ``elinks.action''. + ELinks 0.12pre5: ---------------- diff --git a/doc/smjs-scripting.txt b/doc/smjs-scripting.txt index 34221cd4..155136ad 100644 --- a/doc/smjs-scripting.txt +++ b/doc/smjs-scripting.txt @@ -234,9 +234,10 @@ A history item has these properties: *Compatibility:* ELinks 0.12pre1 NOTE: When you read an action function from this hash, ELinks binds it to the -current tab; any later calls to the function affect that tab. This may be -changed in a future version. It is safest to call the function right away, -rather than save it in a variable and call it later. +current tab; any later calls to the function throw errors if that tab no +longer has the focus (in its terminal). This may be changed in a future +version. It is safest to call the function right away, rather than save it +in a variable and call it later. -- [[smjs-elinks.keymaps]] elinks.keymaps (hash):: diff --git a/src/scripting/smjs/action_object.c b/src/scripting/smjs/action_object.c index 330e21f1..db3203f7 100644 --- a/src/scripting/smjs/action_object.c +++ b/src/scripting/smjs/action_object.c @@ -8,9 +8,11 @@ #include "config/kbdbind.h" #include "ecmascript/spidermonkey-shared.h" +#include "intl/gettext/libintl.h" #include "scripting/smjs/core.h" #include "scripting/smjs/elinks_object.h" #include "session/session.h" +#include "terminal/window.h" #include "util/memory.h" #include "viewer/action.h" @@ -66,6 +68,32 @@ smjs_action_fn_callback(JSContext *ctx, uintN argc, jsval *rval) return JS_TRUE; } + if (!would_window_receive_keypresses(hop->ses->tab)) { + /* The user cannot run actions in this tab by pressing + * keys, and some actions could crash if run in this + * situation; so we don't let user scripts run actions + * either. + * + * In particular, this check should fix bug 943, where + * ::ACT_MAIN_TAB_CLOSE called destroy_session(), + * which freed struct type_query while BFU dialogs had + * pointers to it. That crash could be prevented in + * various ways but it seems other similar crashes are + * possible, e.g. if the link menu is open and has a + * pointer to a session that is then destroyed. + * Instead of thoroughly auditing the use of pointers + * to sessions and related structures, I'll just + * disable the feature, to bring the ELinks 0.12 + * release closer. + * + * The "%s" prevents interpretation of any percent + * signs in translations. */ + JS_ReportError(ctx, "%s", + _("Cannot run actions in a tab that doesn't " + "have the focus", hop->ses->tab->term)); + return JS_FALSE; /* make JS propagate the exception */ + } + if (argc >= 1) { int32 val; diff --git a/src/terminal/window.c b/src/terminal/window.c index b1cf4ad6..f7b1452d 100644 --- a/src/terminal/window.c +++ b/src/terminal/window.c @@ -219,3 +219,25 @@ set_dlg_window_ptr(struct dialog_data *dlg_data, struct window *window, int x, i } set_window_ptr(window, x, y); } + +#if CONFIG_SCRIPTING_SPIDERMONKEY +/** Check whether keypress events would be directed to @a win. */ +int +would_window_receive_keypresses(const struct window *win) +{ + struct terminal *const term = win->term; + const struct window *selected; + + /* At least @win must be in the list. */ + assert(!list_empty(term->windows)); + if_assert_failed return 0; + + selected = term->windows.next; + if (selected->type != WINDOW_TAB) return 0; + + selected = get_current_tab(term); + if (selected != win) return 0; + + return 1; +} +#endif /* CONFIG_SCRIPTING_SPIDERMONKEY */ diff --git a/src/terminal/window.h b/src/terminal/window.h index 0069d7e4..14651a81 100644 --- a/src/terminal/window.h +++ b/src/terminal/window.h @@ -100,4 +100,8 @@ void assert_window_stacking(struct terminal *); #define assert_window_stacking(t) ((void) (t)) #endif +#if CONFIG_SCRIPTING_SPIDERMONKEY +int would_window_receive_keypresses(const struct window *); +#endif + #endif