changeset 19233:04c164c971a3 v8.2.0175

patch 8.2.0175: crash when removing list element in map() Commit: https://github.com/vim/vim/commit/db661fb95dc41b7a9438cf3cd4e77f8410bc81c0 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jan 29 22:17:16 2020 +0100 patch 8.2.0175: crash when removing list element in map() Problem: Crash when removing list element in map(). Solution: Lock the list. (closes https://github.com/vim/vim/issues/2652)
author Bram Moolenaar <Bram@vim.org>
date Wed, 29 Jan 2020 22:30:04 +0100
parents 6d4ef257d300
children c1afd552f030
files src/list.c src/testdir/test_filter_map.vim src/version.c
diffstat 3 files changed, 22 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/list.c
+++ b/src/list.c
@@ -1782,6 +1782,10 @@ filter_map(typval_T *argvars, typval_T *
 
 	if (argvars[0].v_type == VAR_DICT)
 	{
+	    int	    prev_lock = d->dv_lock;
+
+	    if (map && d->dv_lock == 0)
+		d->dv_lock = VAR_LOCKED;
 	    ht = &d->dv_hashtab;
 	    hash_lock(ht);
 	    todo = (int)ht->ht_used;
@@ -1813,6 +1817,7 @@ filter_map(typval_T *argvars, typval_T *
 		}
 	    }
 	    hash_unlock(ht);
+	    d->dv_lock = prev_lock;
 	}
 	else if (argvars[0].v_type == VAR_BLOB)
 	{
@@ -1855,10 +1860,14 @@ filter_map(typval_T *argvars, typval_T *
 	}
 	else // argvars[0].v_type == VAR_LIST
 	{
+	    int prev_lock = l->lv_lock;
+
 	    // set_vim_var_nr() doesn't set the type
 	    set_vim_var_type(VV_KEY, VAR_NUMBER);
 
 	    range_list_materialize(l);
+	    if (map && l->lv_lock == 0)
+		l->lv_lock = VAR_LOCKED;
 	    for (li = l->lv_first; li != NULL; li = nli)
 	    {
 		if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
@@ -1872,6 +1881,7 @@ filter_map(typval_T *argvars, typval_T *
 		    listitem_remove(l, li);
 		++idx;
 	    }
+	    l->lv_lock = prev_lock;
 	}
 
 	restore_vimvar(VV_KEY, &save_key);
--- a/src/testdir/test_filter_map.vim
+++ b/src/testdir/test_filter_map.vim
@@ -93,3 +93,13 @@ func Test_map_fails()
   call assert_fails('call map([1], "42 +")', 'E15:')
   call assert_fails('call filter([1], "42 +")', 'E15:')
 endfunc
+
+func Test_map_and_modify()
+  let l = ["abc"]
+  " cannot change the list halfway a map()
+  call assert_fails('call map(l, "remove(l, 0)[0]")', 'E741:')
+
+  let d = #{a: 1, b: 2, c: 3}
+  call assert_fails('call map(d, "remove(d, v:key)[0]")', 'E741:')
+  call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:')
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -743,6 +743,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    175,
+/**/
     174,
 /**/
     173,