]> granicus.if.org Git - vim/commitdiff
patch 8.0.1067: try/catch in timer does not prevent it from being stopped v8.0.1067
authorBram Moolenaar <Bram@vim.org>
Wed, 6 Sep 2017 21:40:10 +0000 (23:40 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 6 Sep 2017 21:40:10 +0000 (23:40 +0200)
Problem:    Using try/catch in timer does not prevent it from being stopped.
Solution:   Reset the exception context and use did_emsg instead of
            called_emsg.

src/ex_cmds2.c
src/globals.h
src/message.c
src/testdir/test_timers.vim
src/version.c

index 18930a6cfb26764d24effa521028387609c7077e..710a2789e8b4221c8074534bf3feac89657ba05f 100644 (file)
@@ -1219,30 +1219,40 @@ 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;
+           int save_did_emsg = did_emsg;
+           int save_called_emsg = called_emsg;
            int save_must_redraw = must_redraw;
+           int save_trylevel = trylevel;
+           int save_did_throw = did_throw;
+           except_T *save_current_exception = current_exception;
 
+           /* Create a scope for running the timer callback, ignoring most of
+            * the current scope, such as being inside a try/catch. */
            timer_busy = timer_busy > 0 || vgetc_busy > 0;
            vgetc_busy = 0;
            called_emsg = FALSE;
+           did_emsg = FALSE;
+           did_uncaught_emsg = FALSE;
            must_redraw = 0;
+           trylevel = 0;
+           did_throw = FALSE;
+           current_exception = NULL;
+
            timer->tr_firing = TRUE;
            timer_callback(timer);
            timer->tr_firing = FALSE;
+
            timer_next = timer->tr_next;
            did_one = TRUE;
            timer_busy = save_timer_busy;
            vgetc_busy = save_vgetc_busy;
-           if (called_emsg)
-           {
+           if (did_uncaught_emsg)
                ++timer->tr_emsg_count;
-               if (!did_throw_save && did_throw && current_exception != NULL)
-                   discard_current_exception();
-           }
-           did_emsg = did_emsg_save;
-           called_emsg = called_emsg_save;
+           did_emsg = save_did_emsg;
+           called_emsg = save_called_emsg;
+           trylevel = save_trylevel;
+           did_throw = save_did_throw;
+           current_exception = save_current_exception;
            if (must_redraw != 0)
                need_update_screen = TRUE;
            must_redraw = must_redraw > save_must_redraw
index 0b887d35bb6e2ab5e3d48253fc9c886ba70c7197..ac2727f7c802494cb30c541cfa183062b4768eb1 100644 (file)
@@ -182,6 +182,10 @@ EXTERN dict_T      globvardict;                /* Dictionary with g: variables */
 #endif
 EXTERN int     did_emsg;                   /* set by emsg() when the message
                                               is displayed or thrown */
+#ifdef FEAT_EVAL
+EXTERN int     did_uncaught_emsg;          /* emsg() was called and did not
+                                              cause an exception */
+#endif
 EXTERN int     did_emsg_syntax;            /* did_emsg set because of a
                                               syntax error */
 EXTERN int     called_emsg;                /* always set by emsg() */
index 57f33dd87cb1c550e8baec537d8a84cebc3390e3..af22607591f860645511eaaefb04a5ba4aaa0438 100644 (file)
@@ -609,11 +609,9 @@ emsg(char_u *s)
 
     called_emsg = TRUE;
 
-    /*
-     * If "emsg_severe" is TRUE: When an error exception is to be thrown,
-     * prefer this message over previous messages for the same command.
-     */
 #ifdef FEAT_EVAL
+    /* If "emsg_severe" is TRUE: When an error exception is to be thrown,
+     * prefer this message over previous messages for the same command. */
     severe = emsg_severe;
     emsg_severe = FALSE;
 #endif
@@ -684,6 +682,9 @@ emsg(char_u *s)
        else
            flush_buffers(FALSE);       /* flush internal buffers */
        did_emsg = TRUE;                /* flag for DoOneCmd() */
+#ifdef FEAT_EVAL
+       did_uncaught_emsg = TRUE;
+#endif
     }
 
     emsg_on_display = TRUE;    /* remember there is an error message */
index c9171b7b961c7fb161103cda00537332ad2a1fd4..b5b9d67db1a4a9546835ee2595bf08b72f2ffcd8 100644 (file)
@@ -208,6 +208,24 @@ func Test_timer_errors()
   call assert_equal(3, g:call_count)
 endfunc
 
+func FuncWithCaughtError(timer)
+  let g:call_count += 1
+  try
+    doesnotexist
+  catch
+    " nop
+  endtry
+endfunc
+
+func Test_timer_catch_error()
+  let g:call_count = 0
+  let timer = timer_start(10, 'FuncWithCaughtError', {'repeat': 4})
+  " Timer will not be stopped.
+  call WaitFor('g:call_count == 4')
+  sleep 50m
+  call assert_equal(4, g:call_count)
+endfunc
+
 func FeedAndPeek(timer)
   call test_feedinput('a')
   call getchar(1)
index a3ab6edf54b04b8907d984167b3f590a02594982..2ce3d26d37403bb1a95822b82b84029a08f11e00 100644 (file)
@@ -769,6 +769,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1067,
 /**/
     1066,
 /**/