summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-01-29 22:17:16 +0100
committerBram Moolenaar <Bram@vim.org>2020-01-29 22:17:16 +0100
commitdb661fb95dc41b7a9438cf3cd4e77f8410bc81c0 (patch)
treeabaa599d8defc53879ca396f43f5fe816e21709e
parent5d98dc2a48156d44139b75c689bd3137ff7fe8bf (diff)
downloadvim-git-8.2.0175.tar.gz
patch 8.2.0175: crash when removing list element in map()v8.2.0175
Problem: Crash when removing list element in map(). Solution: Lock the list. (closes #2652)
-rw-r--r--src/list.c10
-rw-r--r--src/testdir/test_filter_map.vim10
-rw-r--r--src/version.c2
3 files changed, 22 insertions, 0 deletions
diff --git a/src/list.c b/src/list.c
index 855a20d07..518423b71 100644
--- a/src/list.c
+++ b/src/list.c
@@ -1782,6 +1782,10 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
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 *rettv, int map)
}
}
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 *rettv, int map)
}
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 *rettv, int map)
listitem_remove(l, li);
++idx;
}
+ l->lv_lock = prev_lock;
}
restore_vimvar(VV_KEY, &save_key);
diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim
index e144538de..577e0ce0b 100644
--- 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
diff --git a/src/version.c b/src/version.c
index df1fe0d04..0306e4722 100644
--- 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,