summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-10-07 11:20:29 +0100
committerBram Moolenaar <Bram@vim.org>2022-10-07 11:20:29 +0100
commitcf3d0eaf47a56a52b355d8faf4e59685396f9c05 (patch)
treeecb982bc178f8eaab7f8a12436d83526778ff331
parent0937b9fb244949b7ce9bfcf8398d7495b9b6aa85 (diff)
patch 9.0.0682: crash when popup with deleted timer is closedv9.0.0682
Problem: Crash when popup with deleted timer is closed. (Igbanam Ogbuluijah) Solution: Check the timer still exists. (closes #11301)
-rw-r--r--src/proto/time.pro1
-rw-r--r--src/testdir/test_timers.vim14
-rw-r--r--src/time.c18
-rw-r--r--src/version.c2
-rw-r--r--src/window.c3
5 files changed, 34 insertions, 4 deletions
diff --git a/src/proto/time.pro b/src/proto/time.pro
index affdb7a6d5..7e44bca1b7 100644
--- a/src/proto/time.pro
+++ b/src/proto/time.pro
@@ -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);
diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim
index 9183e13df2..1b996c523d 100644
--- a/src/testdir/test_timers.vim
+++ b/src/testdir/test_timers.vim
@@ -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
diff --git a/src/time.c b/src/time.c
index 901222c195..f8e8c5afe2 100644
--- a/src/time.c
+++ b/src/time.c
@@ -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);
}
diff --git a/src/version.c b/src/version.c
index bd93ff703c..37ece8919c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 682,
+/**/
681,
/**/
680,
diff --git a/src/window.c b/src/window.c
index f63b8564fb..8486f1a5e9 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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);