summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2023-03-19 21:23:38 +0000
committerBram Moolenaar <Bram@vim.org>2023-03-19 21:23:38 +0000
commite6d40dcdc7227594935d2db01eca29f0e575dcee (patch)
treecceadc9510c19f5ba8f99e26954bf8fbef40b6d6
parent7c4516fe93d865f4ef1877181f8156b8b9331856 (diff)
patch 9.0.1416: crash when collection is modified when using filter()v9.0.1416
Problem: Crash when collection is modified when using filter(). Solution: Lock the list/dict/blob. (Ernie Rael, closes #12183)
-rw-r--r--src/blob.c11
-rw-r--r--src/dict.c8
-rw-r--r--src/list.c12
-rw-r--r--src/proto/blob.pro2
-rw-r--r--src/testdir/test_filter_map.vim15
-rw-r--r--src/version.c2
6 files changed, 36 insertions, 14 deletions
diff --git a/src/blob.c b/src/blob.c
index bfc77231ce..6f4297345d 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -592,9 +592,10 @@ blob_filter_map(
blob_T *blob_arg,
filtermap_T filtermap,
typval_T *expr,
+ char_u *arg_errmsg,
typval_T *rettv)
{
- blob_T *b;
+ blob_T *b = blob_arg;
int i;
typval_T tv;
varnumber_T val;
@@ -609,7 +610,8 @@ blob_filter_map(
rettv->v_type = VAR_BLOB;
rettv->vval.v_blob = NULL;
}
- if ((b = blob_arg) == NULL)
+ if (b == NULL || (filtermap == FILTERMAP_FILTER
+ && value_check_lock(b->bv_lock, arg_errmsg, TRUE)))
return;
b_ret = b;
@@ -623,6 +625,10 @@ blob_filter_map(
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
+ int prev_lock = b->bv_lock;
+ if (b->bv_lock == 0)
+ b->bv_lock = VAR_LOCKED;
+
// Create one funccal_T for all eval_expr_typval() calls.
fc = eval_expr_get_funccal(expr, &newtv);
@@ -658,6 +664,7 @@ blob_filter_map(
++idx;
}
+ b->bv_lock = prev_lock;
if (fc != NULL)
remove_funccal();
}
diff --git a/src/dict.c b/src/dict.c
index 74501ffe31..1ce01c15b6 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -1305,7 +1305,7 @@ dict_extend_func(
action = (char_u *)"force";
if (type != NULL && check_typval_arg_type(type, &argvars[1],
- func_name, 2) == FAIL)
+ func_name, 2) == FAIL)
return;
dict_extend(d1, d2, action, func_name);
@@ -1333,7 +1333,6 @@ dict_filter_map(
typval_T *expr,
typval_T *rettv)
{
- int prev_lock;
dict_T *d_ret = NULL;
hashtab_T *ht;
hashitem_T *hi;
@@ -1353,8 +1352,6 @@ dict_filter_map(
&& value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
return;
- prev_lock = d->dv_lock;
-
if (filtermap == FILTERMAP_MAPNEW)
{
if (rettv_dict_alloc(rettv) == FAIL)
@@ -1365,7 +1362,8 @@ dict_filter_map(
// Create one funccal_T for all eval_expr_typval() calls.
fc = eval_expr_get_funccal(expr, &newtv);
- if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
+ int prev_lock = d->dv_lock;
+ if (d->dv_lock == 0)
d->dv_lock = VAR_LOCKED;
ht = &d->dv_hashtab;
hash_lock(ht);
diff --git a/src/list.c b/src/list.c
index 991be8b01f..1bb63b0700 100644
--- a/src/list.c
+++ b/src/list.c
@@ -2398,7 +2398,7 @@ list_filter_map(
// set_vim_var_nr() doesn't set the type
set_vim_var_type(VV_KEY, VAR_NUMBER);
- if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
+ if (l->lv_lock == 0)
l->lv_lock = VAR_LOCKED;
// Create one funccal_T for all eval_expr_typval() calls.
@@ -2576,15 +2576,15 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
if (argvars[0].v_type == VAR_DICT)
dict_filter_map(argvars[0].vval.v_dict, filtermap, type, func_name,
- arg_errmsg, expr, rettv);
+ arg_errmsg, expr, rettv);
else if (argvars[0].v_type == VAR_BLOB)
- blob_filter_map(argvars[0].vval.v_blob, filtermap, expr, rettv);
+ blob_filter_map(argvars[0].vval.v_blob, filtermap, expr,
+ arg_errmsg, rettv);
else if (argvars[0].v_type == VAR_STRING)
- string_filter_map(tv_get_string(&argvars[0]), filtermap, expr,
- rettv);
+ string_filter_map(tv_get_string(&argvars[0]), filtermap, expr, rettv);
else // argvars[0].v_type == VAR_LIST
list_filter_map(argvars[0].vval.v_list, filtermap, type, func_name,
- arg_errmsg, expr, rettv);
+ arg_errmsg, expr, rettv);
restore_vimvar(VV_KEY, &save_key);
restore_vimvar(VV_VAL, &save_val);
diff --git a/src/proto/blob.pro b/src/proto/blob.pro
index 7c8b5ac815..06959aa7b5 100644
--- a/src/proto/blob.pro
+++ b/src/proto/blob.pro
@@ -20,7 +20,7 @@ int check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet);
int blob_set_range(blob_T *dest, long n1, long n2, typval_T *src);
void blob_add(typval_T *argvars, typval_T *rettv);
void blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg);
-void blob_filter_map(blob_T *blob_arg, filtermap_T filtermap, typval_T *expr, typval_T *rettv);
+void blob_filter_map(blob_T *blob_arg, filtermap_T filtermap, typval_T *expr, char_u *arg_errmsg, typval_T *rettv);
void blob_insert_func(typval_T *argvars, typval_T *rettv);
void blob_reduce(typval_T *argvars, typval_T *expr, typval_T *rettv);
void blob_reverse(blob_T *b, typval_T *rettv);
diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim
index f06059b554..6a07bec215 100644
--- a/src/testdir/test_filter_map.vim
+++ b/src/testdir/test_filter_map.vim
@@ -116,6 +116,21 @@ func Test_map_and_modify()
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:')
+
+ let b = 0z1234
+ call assert_fails('call filter(b, "remove(b, 0)")', 'E741:')
+endfunc
+
+func Test_filter_and_modify()
+ let l = [0]
+ " cannot change the list halfway a map()
+ call assert_fails('call filter(l, "remove(l, 0)")', 'E741:')
+
+ let d = #{a: 0, b: 0, c: 0}
+ call assert_fails('call filter(d, "remove(d, v:key)")', 'E741:')
+
+ let b = 0z1234
+ call assert_fails('call filter(b, "remove(b, 0)")', 'E741:')
endfunc
func Test_mapnew_dict()
diff --git a/src/version.c b/src/version.c
index 585f72c1b8..41960f8909 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1416,
+/**/
1415,
/**/
1414,