0
0
mirror of https://github.com/vim/vim.git synced 2025-10-09 06:14:17 -04:00

patch 8.0.0702: an error in a timer can make Vim unusable

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.
This commit is contained in:
Bram Moolenaar
2017-07-08 22:37:34 +02:00
parent 11e79bb04e
commit c577d813b7
5 changed files with 50 additions and 10 deletions

View File

@@ -1197,11 +1197,13 @@ check_due_timer(void)
long current_id = last_timer_id;
# ifdef WIN3264
LARGE_INTEGER fr;
# endif
/* Don't run any timers while exiting. */
if (exiting)
/* Don't run any timers while exiting or dealing with an error. */
if (exiting || aborting())
return next_due;
# ifdef WIN3264
QueryPerformanceFrequency(&fr);
# endif
profile_start(&now);
@@ -1216,9 +1218,13 @@ check_due_timer(void)
{
int save_timer_busy = timer_busy;
int save_vgetc_busy = vgetc_busy;
int did_emsg_save = did_emsg;
int called_emsg_save = called_emsg;
int did_throw_save = did_throw;
timer_busy = timer_busy > 0 || vgetc_busy > 0;
vgetc_busy = 0;
called_emsg = FALSE;
timer->tr_firing = TRUE;
timer_callback(timer);
timer->tr_firing = FALSE;
@@ -1226,10 +1232,19 @@ check_due_timer(void)
did_one = TRUE;
timer_busy = save_timer_busy;
vgetc_busy = save_vgetc_busy;
if (called_emsg)
{
++timer->tr_emsg_count;
if (!did_throw_save && current_exception != NULL)
discard_current_exception();
}
did_emsg = did_emsg_save;
called_emsg = called_emsg_save;
/* Only fire the timer again if it repeats and stop_timer() wasn't
* called while inside the callback (tr_id == -1). */
if (timer->tr_repeat != 0 && timer->tr_id != -1)
if (timer->tr_repeat != 0 && timer->tr_id != -1
&& timer->tr_emsg_count < 3)
{
profile_setlimit(timer->tr_interval, &timer->tr_due);
this_due = GET_TIMEDIFF(timer, now);

View File

@@ -3243,6 +3243,7 @@ struct timer_S
long tr_interval; /* msec */
char_u *tr_callback; /* allocated */
partial_T *tr_partial;
int tr_emsg_count;
#endif
};

View File

@@ -189,4 +189,22 @@ func Test_input_in_timer()
call assert_equal('hello', g:val)
endfunc
func FuncWithError(timer)
let g:call_count += 1
if g:call_count == 4
return
endif
doesnotexist
endfunc
func Test_timer_errors()
let g:call_count = 0
let timer = timer_start(10, 'FuncWithError', {'repeat': -1})
" Timer will be stopped after failing 3 out of 3 times.
call WaitFor('g:call_count == 3')
sleep 50m
call assert_equal(3, g:call_count)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
702,
/**/
701,
/**/