# HG changeset patch # User Christian Brabandt # Date 1464722106 -7200 # Node ID c2fe86f2bda155996f570d56b632f73a9d4ab00f # Parent b780d4eac8c735a4ec787e546650b6c5e4523854 commit https://github.com/vim/vim/commit/e3188e261569ae512fb1ae2653b57fdd9e259ca3 Author: Bram Moolenaar Date: Tue May 31 21:13:04 2016 +0200 patch 7.4.1860 Problem: Using a partial for timer_start() may cause a crash. Solution: Set the copyID in timer objects. (Ozaki Kiichi) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -7046,6 +7046,10 @@ garbage_collect(int testing) abort = abort || set_ref_in_nb_channel(copyID); #endif +#ifdef FEAT_TIMERS + abort = abort || set_ref_in_timer(copyID); +#endif + if (!abort) { /* diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -1252,6 +1252,25 @@ stop_timer(timer_T *timer) remove_timer(timer); free_timer(timer); } + +/* + * Mark references in partials of timers. + */ + int +set_ref_in_timer(int copyID) +{ + int abort = FALSE; + timer_T *timer; + typval_T tv; + + for (timer = first_timer; timer != NULL; timer = timer->tr_next) + { + tv.v_type = VAR_PARTIAL; + tv.vval.v_partial = timer->tr_partial; + abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); + } + return abort; +} # endif #if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT) diff --git a/src/proto/ex_cmds2.pro b/src/proto/ex_cmds2.pro --- a/src/proto/ex_cmds2.pro +++ b/src/proto/ex_cmds2.pro @@ -22,6 +22,7 @@ timer_T *create_timer(long msec, int rep long check_due_timer(void); timer_T *find_timer(int id); void stop_timer(timer_T *timer); +int set_ref_in_timer(int copyID); void profile_divide(proftime_T *tm, int count, proftime_T *tm2); void profile_add(proftime_T *tm, proftime_T *tm2); void profile_self(proftime_T *self, proftime_T *total, proftime_T *children); diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim --- a/src/testdir/test_timers.vim +++ b/src/testdir/test_timers.vim @@ -8,6 +8,10 @@ func MyHandler(timer) let s:val += 1 endfunc +func MyHandlerWithLists(lists, timer) + let x = string(a:lists) +endfunc + func Test_oneshot() let s:val = 0 let timer = timer_start(50, 'MyHandler') @@ -42,4 +46,10 @@ func Test_with_partial_callback() sleep 200m call assert_equal(1, s:val) endfunc + +func Test_retain_partial() + call timer_start(100, function('MyHandlerWithLists', [['a']])) + call test_garbagecollect_now() + sleep 200m +endfunc " vim: ts=2 sw=0 et diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1860, +/**/ 1859, /**/ 1858,