]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1416: crash when collection is modified when using filter() v9.0.1416
authorErnie Rael <errael@raelity.com>
Sun, 19 Mar 2023 21:23:38 +0000 (21:23 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 19 Mar 2023 21:23:38 +0000 (21:23 +0000)
Problem:    Crash when collection is modified when using filter().
Solution:   Lock the list/dict/blob. (Ernie Rael, closes #12183)

src/blob.c
src/dict.c
src/list.c
src/proto/blob.pro
src/testdir/test_filter_map.vim
src/version.c

index bfc77231ce95d82f063b0a8be557c7d779eebd98..6f4297345d83980b1713b5b25c813641d89658a8 100644 (file)
@@ -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();
 }
index 74501ffe31ae86b171170b594da11f115016e2f0..1ce01c15b61a653619e77a49bafc17eb5d65943d 100644 (file)
@@ -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);
index 991be8b01fa3935f8806a0dee7c8ef1a9e853f07..1bb63b0700ee9f9a43fcc1b7e6c7901eb82ff28a 100644 (file)
@@ -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);
index 7c8b5ac8158b1f16b62e7bda99b3da654cc7677e..06959aa7b51fd637d94400fee6c253cba30242ac 100644 (file)
@@ -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);
index f06059b5549c923b86acf6dc0d9b76fef86eede7..6a07bec21517df999660332a3aed91a55a4669f8 100644 (file)
@@ -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()
index 585f72c1b8fc5ccb046ef44acd3f22398db2284c..41960f890901d382531927e4cd452c907b4f6fb7 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1416,
 /**/
     1415,
 /**/