mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.3426: crash when deleting a listener in a listener callback
Problem: Crash when deleting a listener in a listener callback. (Naohiro Ono) Solution: Mark the listener and delete it later.
This commit is contained in:
parent
56e14698b4
commit
4b4b1b84ee
38
src/change.c
38
src/change.c
@ -293,6 +293,18 @@ f_listener_flush(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
invoke_listeners(buf);
|
invoke_listeners(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_listener(buf_T *buf, listener_T *lnr, listener_T *prev)
|
||||||
|
{
|
||||||
|
if (prev != NULL)
|
||||||
|
prev->lr_next = lnr->lr_next;
|
||||||
|
else
|
||||||
|
buf->b_listener = lnr->lr_next;
|
||||||
|
free_callback(&lnr->lr_callback);
|
||||||
|
vim_free(lnr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* listener_remove() function
|
* listener_remove() function
|
||||||
*/
|
*/
|
||||||
@ -317,12 +329,13 @@ f_listener_remove(typval_T *argvars, typval_T *rettv)
|
|||||||
next = lnr->lr_next;
|
next = lnr->lr_next;
|
||||||
if (lnr->lr_id == id)
|
if (lnr->lr_id == id)
|
||||||
{
|
{
|
||||||
if (prev != NULL)
|
if (textwinlock > 0)
|
||||||
prev->lr_next = lnr->lr_next;
|
{
|
||||||
else
|
// in invoke_listeners(), clear ID and delete later
|
||||||
buf->b_listener = lnr->lr_next;
|
lnr->lr_id = 0;
|
||||||
free_callback(&lnr->lr_callback);
|
return;
|
||||||
vim_free(lnr);
|
}
|
||||||
|
remove_listener(buf, lnr, prev);
|
||||||
rettv->vval.v_number = 1;
|
rettv->vval.v_number = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -357,6 +370,7 @@ invoke_listeners(buf_T *buf)
|
|||||||
linenr_T added = 0;
|
linenr_T added = 0;
|
||||||
int save_updating_screen = updating_screen;
|
int save_updating_screen = updating_screen;
|
||||||
static int recursive = FALSE;
|
static int recursive = FALSE;
|
||||||
|
listener_T *next;
|
||||||
|
|
||||||
if (buf->b_recorded_changes == NULL // nothing changed
|
if (buf->b_recorded_changes == NULL // nothing changed
|
||||||
|| buf->b_listener == NULL // no listeners
|
|| buf->b_listener == NULL // no listeners
|
||||||
@ -400,6 +414,18 @@ invoke_listeners(buf_T *buf)
|
|||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If f_listener_remove() was called may have to remove a listener now.
|
||||||
|
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);
|
||||||
|
else
|
||||||
|
prev = lnr;
|
||||||
|
}
|
||||||
|
|
||||||
--textwinlock;
|
--textwinlock;
|
||||||
list_unref(buf->b_recorded_changes);
|
list_unref(buf->b_recorded_changes);
|
||||||
buf->b_recorded_changes = NULL;
|
buf->b_recorded_changes = NULL;
|
||||||
|
@ -370,4 +370,22 @@ func Test_col_after_deletion_moved_cur()
|
|||||||
delfunc Listener
|
delfunc Listener
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_remove_listener_in_callback()
|
||||||
|
new
|
||||||
|
let s:ID = listener_add('Listener')
|
||||||
|
func Listener(...)
|
||||||
|
call listener_remove(s:ID)
|
||||||
|
let g:listener_called = 'yes'
|
||||||
|
endfunc
|
||||||
|
call setline(1, ['foo'])
|
||||||
|
call feedkeys("lD", 'xt')
|
||||||
|
call listener_flush()
|
||||||
|
call assert_equal('yes', g:listener_called)
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
delfunc Listener
|
||||||
|
unlet g:listener_called
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -755,6 +755,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3426,
|
||||||
/**/
|
/**/
|
||||||
3425,
|
3425,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user