diff --git a/src/change.c b/src/change.c index fe2a732c38..527d2cc8c0 100644 --- a/src/change.c +++ b/src/change.c @@ -297,7 +297,6 @@ may_record_change( if (curbuf->b_recorded_changes == NULL) // out of memory return; ++curbuf->b_recorded_changes->lv_refcount; - curbuf->b_recorded_changes->lv_lock = VAR_FIXED; } dict = dict_alloc(); @@ -489,6 +488,7 @@ invoke_listener_set( listener_T *lnr; typval_T rettv; typval_T argv[6]; + typval_T val; argv[0].v_type = VAR_NUMBER; argv[0].vval.v_number = buf->b_fnum; // a:bufnr @@ -501,6 +501,13 @@ invoke_listener_set( argv[4].v_type = VAR_LIST; argv[4].vval.v_list = recorded_changes; + // Ensure the list of changes is locked to prevent any modifications by + // callback code.. + val.v_type = VAR_LIST; + val.v_lock = 0; + val.vval.v_list = recorded_changes; + item_lock(&val, -1, TRUE, FALSE); + // Protect against recursive callbacks, lock the buffer against changes and // set the updating_screen flag to prevent channel input processing, which // might also try to update the buffer. @@ -547,7 +554,6 @@ invoke_sync_listeners( return; ++recorded_changes->lv_refcount; - recorded_changes->lv_lock = VAR_FIXED; dict = dict_alloc(); if (dict == NULL) diff --git a/src/testdir/test_listener.vim b/src/testdir/test_listener.vim index 88e4a3f785..7fc985ec98 100644 --- a/src/testdir/test_listener.vim +++ b/src/testdir/test_listener.vim @@ -21,8 +21,21 @@ func s:AnotherStoreList(l) endfunc func s:EvilStoreList(l) + func! Modify_dict_in_list(the_list, key) + let a:the_list[0][a:key] = a:the_list[0][a:key] + 1 + endfunc + func! Modify_list_entry(the_list) + let a:the_list[0] = 42 + endfunc + let s:list3 = a:l - call assert_fails("call add(a:l, 'myitem')", "E742:") + call assert_fails("call add(a:l, 'myitem')", "E741:") + call assert_fails("call remove(a:l, 1)", "E741:") + call assert_fails("call Modify_dict_in_list(a:l, 'lnum')", "E741:") + call assert_fails("call Modify_dict_in_list(a:l, 'end')", "E741:") + call assert_fails("call Modify_dict_in_list(a:l, 'col')", "E741:") + call assert_fails("call Modify_dict_in_list(a:l, 'added')", "E741:") + call assert_fails("call Modify_list_entry(a:l)", "E741:") endfunc func Test_listening() diff --git a/src/version.c b/src/version.c index f48b3d79e6..80071eab63 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1792, /**/ 1791, /**/