aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2019-04-10 00:50:51 +0200
committerJustin M. Keyes <justinkz@gmail.com>2019-04-10 00:50:51 +0200
commit9d085c75ff427bf0ccc408983ce7b68f0a2b284d (patch)
tree66ff0f2aa1cd79ef8ec19f80ab473d7be770cd60 /src/nvim/eval.c
parentae2401621abbf530f5abd1ad8ce822b739b02cc4 (diff)
downloadrneovim-9d085c75ff427bf0ccc408983ce7b68f0a2b284d.tar.gz
rneovim-9d085c75ff427bf0ccc408983ce7b68f0a2b284d.tar.bz2
rneovim-9d085c75ff427bf0ccc408983ce7b68f0a2b284d.zip
vim-patch:8.0.0702: error in a timer can make Vim unusable #9826
Problem: An error in a timer can make Vim unusable. Solution: Don't set the error flag or exception from a timer. Stop a timer if it causes an error 3 out of 3 times. Discard an exception caused inside a timer. https://github.com/vim/vim/commit/c577d813b7978345dec4310b2d8f5d5624a681f6 closes #9826
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 929304a874..9a67b01307 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -449,6 +449,7 @@ typedef struct {
int timer_id;
int repeat_count;
int refcount;
+ int emsg_count; ///< Errors in a repeating timer.
long timeout;
bool stopped;
bool paused;
@@ -17160,6 +17161,7 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
timer->refcount = 1;
timer->stopped = false;
timer->paused = false;
+ timer->emsg_count = 0;
timer->repeat_count = repeat;
timer->timeout = timeout;
timer->timer_id = last_timer_id++;
@@ -17202,6 +17204,9 @@ static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr)
static void timer_due_cb(TimeWatcher *tw, void *data)
{
timer_T *timer = (timer_T *)data;
+ int save_did_emsg = did_emsg;
+ int save_called_emsg = called_emsg;
+
if (timer->stopped || timer->paused) {
return;
}
@@ -17216,8 +17221,24 @@ static void timer_due_cb(TimeWatcher *tw, void *data)
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = timer->timer_id;
typval_T rettv = TV_INITIAL_VALUE;
+ called_emsg = false;
callback_call(&timer->callback, 1, argv, &rettv);
+
+ // Handle error message
+ if (called_emsg && did_emsg) {
+ timer->emsg_count++;
+ if (current_exception != NULL) {
+ discard_current_exception();
+ }
+ }
+ did_emsg = save_did_emsg;
+ called_emsg = save_called_emsg;
+
+ if (timer->emsg_count >= 3) {
+ timer_stop(timer);
+ }
+
tv_clear(&rettv);
if (!timer->stopped && timer->timeout == 0) {