# HG changeset patch # User Bram Moolenaar # Date 1662135303 -7200 # Node ID 711ae604980a8b2ea2619d79a75e4901ad9cab95 # Parent c84bafac81accc54412478f3b61c6b291296e09a patch 9.0.0361: removing a listener may result in a memory leak Commit: https://github.com/vim/vim/commit/956be4678fba2051a8d24c15cc5dc67fb89c515f Author: Yegappan Lakshmanan Date: Fri Sep 2 17:12:07 2022 +0100 patch 9.0.0361: removing a listener may result in a memory leak Problem: Removing a listener may result in a memory leak and remove subsequent listerns. Solution: Init the "prev" pointer only once. (Yegappan Lakshmanan, closes #11039) diff --git a/src/change.c b/src/change.c --- a/src/change.c +++ b/src/change.c @@ -362,6 +362,7 @@ invoke_listeners(buf_T *buf) int save_updating_screen = updating_screen; static int recursive = FALSE; listener_T *next; + listener_T *prev; if (buf->b_recorded_changes == NULL // nothing changed || buf->b_listener == NULL // no listeners @@ -406,10 +407,9 @@ invoke_listeners(buf_T *buf) } // If f_listener_remove() was called may have to remove a listener now. + prev = NULL; for (lnr = buf->b_listener; lnr != NULL; lnr = next) { - listener_T *prev = NULL; - next = lnr->lr_next; if (lnr->lr_id == 0) remove_listener(buf, lnr, prev); diff --git a/src/testdir/test_listener.vim b/src/testdir/test_listener.vim --- a/src/testdir/test_listener.vim +++ b/src/testdir/test_listener.vim @@ -387,6 +387,37 @@ func Test_remove_listener_in_callback() unlet g:listener_called endfunc +" When multiple listeners are registered, remove one listener and verify the +" other listener is still called +func Test_remove_one_listener_in_callback() + new + let g:listener1_called = 0 + let g:listener2_called = 0 + let s:ID1 = listener_add('Listener1') + let s:ID2 = listener_add('Listener2') + func Listener1(...) + call listener_remove(s:ID1) + let g:listener1_called += 1 + endfunc + func Listener2(...) + let g:listener2_called += 1 + endfunc + call setline(1, ['foo']) + call feedkeys("~", 'xt') + call listener_flush() + call feedkeys("~", 'xt') + call listener_flush() + call assert_equal(1, g:listener1_called) + call assert_equal(2, g:listener2_called) + + call listener_remove(s:ID2) + bwipe! + delfunc Listener1 + delfunc Listener2 + unlet g:listener1_called + unlet g:listener2_called +endfunc + func Test_no_change_for_empty_undo() new let text = ['some word here', 'second line'] diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -708,6 +708,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 361, +/**/ 360, /**/ 359,