]> granicus.if.org Git - vim/commitdiff
patch 9.0.0682: crash when popup with deleted timer is closed v9.0.0682
authorBram Moolenaar <Bram@vim.org>
Fri, 7 Oct 2022 10:20:29 +0000 (11:20 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 7 Oct 2022 10:20:29 +0000 (11:20 +0100)
Problem:    Crash when popup with deleted timer is closed. (Igbanam
            Ogbuluijah)
Solution:   Check the timer still exists. (closes #11301)

src/proto/time.pro
src/testdir/test_timers.vim
src/time.c
src/version.c
src/window.c

index affdb7a6d55938e2c8bef772966ac3ea5adf9c58..7e44bca1b7c8fcbbcc6382d2183bf24d57fa10c3 100644 (file)
@@ -13,6 +13,7 @@ void timer_start(timer_T *timer);
 long check_due_timer(void);
 void stop_timer(timer_T *timer);
 int set_ref_in_timer(int copyID);
+int timer_valid(timer_T *timer);
 void timer_free_all(void);
 void f_timer_info(typval_T *argvars, typval_T *rettv);
 void f_timer_pause(typval_T *argvars, typval_T *rettv);
index 9183e13df2c0906930f8e74b088ac25cd2eeae63..1b996c523defad2a62305a120881c1943398cee7 100644 (file)
@@ -137,6 +137,20 @@ func Test_timer_stopall()
   call assert_equal(0, len(info))
 endfunc
 
+def Test_timer_stopall_with_popup()
+  # Create a popup that times out after ten seconds.
+  # Another timer will fire in half a second and close it early after stopping
+  # all timers.
+  var pop = popup_create('Popup', {time: 10000})
+  var tmr = timer_start(500, (_) => {
+    timer_stopall()
+    popup_clear()
+  })
+  sleep 1
+  assert_equal([], timer_info(tmr))
+  assert_equal([], popup_list())
+enddef
+
 func Test_timer_paused()
   let g:test_is_flaky = 1
   let g:val = 0
index 901222c195822fe97d7fbc505d03be3136969721..f8e8c5afe29961fb0c0dcb6c9a038ac9d4134993 100644 (file)
@@ -777,15 +777,27 @@ set_ref_in_timer(int copyID)
     return abort;
 }
 
+/*
+ * Return TRUE if "timer" exists in the list of timers.
+ */
+    int
+timer_valid(timer_T *timer)
+{
+    if (timer == NULL)
+       return FALSE;
+    for (timer_T *t = first_timer; t != NULL; t = t->tr_next)
+       if (t == timer)
+           return TRUE;
+    return FALSE;
+}
+
 # if defined(EXITFREE) || defined(PROTO)
     void
 timer_free_all()
 {
-    timer_T *timer;
-
     while (first_timer != NULL)
     {
-       timer = first_timer;
+       timer_T *timer = first_timer;
        remove_timer(timer);
        free_timer(timer);
     }
index bd93ff703cf33a444128b232fafc6b9fdb22d899..37ece8919cf2f245f86a67a11f1b9ffa21031130 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    682,
 /**/
     681,
 /**/
index f63b8564fbc9d2ed229585022d242f9dbc24ae19..8486f1a5e91d2ca7815fec3de56c7e20c735100c 100644 (file)
@@ -5322,7 +5322,8 @@ win_free_popup(win_T *win)
            close_buffer(win, win->w_buffer, 0, FALSE, FALSE);
     }
 # if defined(FEAT_TIMERS)
-    if (win->w_popup_timer != NULL)
+    // the timer may have been cleared, making the pointer invalid
+    if (timer_valid(win->w_popup_timer))
        stop_timer(win->w_popup_timer);
 # endif
     vim_free(win->w_frame);