]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2325: Vim9: crash if map() changes the item type v8.2.2325
authorBram Moolenaar <Bram@vim.org>
Sun, 10 Jan 2021 21:42:50 +0000 (22:42 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 10 Jan 2021 21:42:50 +0000 (22:42 +0100)
Problem:    Vim9: crash if map() changes the item type.
Solution:   Check that the item type is still OK. (closes #7652)
            Fix problem with mapnew() on range list.

src/evalfunc.c
src/list.c
src/proto/evalfunc.pro
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c

index 85f8befff61bcb4d5bf8b0d4452f52a900f9279c..1abcd5e11ccecba7673b1b2c166834878306af69 100644 (file)
@@ -1929,6 +1929,15 @@ internal_func_ret_type(int idx, int argcount, type_T **argtypes)
     return global_functions[idx].f_retfunc(argcount, argtypes);
 }
 
+/*
+ * Return TRUE if "idx" is for the map() function.
+ */
+    int
+internal_func_is_map(int idx)
+{
+    return global_functions[idx].f_func == f_map;
+}
+
 /*
  * Check the argument count to use for internal function "idx".
  * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
index 4531e5885a126d896a08d526e341ef00d60adde2..2b44ebacb85d670d8382450a25296ecdff7ac0ab 100644 (file)
@@ -2188,10 +2188,13 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
                int             stride = l->lv_u.nonmat.lv_stride;
 
                // List from range(): loop over the numbers
-               l->lv_first = NULL;
-               l->lv_u.mat.lv_last = NULL;
-               l->lv_len = 0;
-               l->lv_u.mat.lv_idx_item = NULL;
+               if (filtermap != FILTERMAP_MAPNEW)
+               {
+                   l->lv_first = NULL;
+                   l->lv_u.mat.lv_last = NULL;
+                   l->lv_len = 0;
+                   l->lv_u.mat.lv_idx_item = NULL;
+               }
 
                for (idx = 0; idx < len; ++idx)
                {
index 562a7c83d9072786169afe217c2481768b23dd8c..ad4b98a29d872a49b83d4edaeb7d61a0be409375 100644 (file)
@@ -6,6 +6,7 @@ int has_internal_func(char_u *name);
 char *internal_func_name(int idx);
 int internal_func_check_arg_types(type_T **types, int idx, int argcount);
 type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
+int internal_func_is_map(int idx);
 int check_internal_func(int idx, int argcount);
 int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
 void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv);
index 7aef315dc869329f71281c3e315ac72d494cee4a..673f0c05627226a506f1c6bf8c2f00eb19a07869 100644 (file)
@@ -231,7 +231,7 @@ def Test_extend_arg_types()
   assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, s:string_keep))
 
   var res: list<dict<any>>
-  extend(res, map([1, 2], (_, v) => ({})))
+  extend(res, mapnew([1, 2], (_, v) => ({})))
   assert_equal([{}, {}], res)
 
   CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, expected list<number> but got number')
@@ -320,6 +320,15 @@ def Test_map_function_arg()
   CheckDefAndScriptSuccess(lines)
 enddef
 
+def Test_map_item_type()
+  var lines =<< trim END
+      var l = ['a', 'b', 'c']
+      map(l, (k, v) => k .. '/' .. v )
+      assert_equal(['0/a', '1/b', '2/c'], l)
+  END
+  CheckDefAndScriptSuccess(lines)
+enddef
+
 def Test_filereadable()
   assert_false(filereadable(""))
   assert_false(filereadable(test_null_string()))
@@ -728,7 +737,7 @@ enddef
 
 def Test_submatch()
   var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
-  var Rep = () => range(10)->map((_, v) => submatch(v, true))->string()
+  var Rep = () => range(10)->mapnew((_, v) => submatch(v, true))->string()
   var actual = substitute('A123456789', pat, Rep, '')
   var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]"
   actual->assert_equal(expected)
index 8955a7ccf0867d47db9980b14847d91c409f7189..50537c858aa6f7a7f626f2aad2f5cafe31c53099 100644 (file)
@@ -1859,10 +1859,10 @@ def Test_expr7_lambda()
 
       # line continuation inside lambda with "cond ? expr : expr" works
       var ll = range(3)
-      map(ll, (k, v) => v % 2 ? {
+      var dll = mapnew(ll, (k, v) => v % 2 ? {
                 ['111']: 111 } : {}
             )
-      assert_equal([{}, {111: 111}, {}], ll)
+      assert_equal([{}, {111: 111}, {}], dll)
 
       ll = range(3)
       map(ll, (k, v) => v == 8 || v
@@ -1946,10 +1946,10 @@ def Test_expr7_new_lambda()
 
       # line continuation inside lambda with "cond ? expr : expr" works
       var ll = range(3)
-      map(ll, (k, v) => v % 2 ? {
+      var dll = mapnew(ll, (k, v) => v % 2 ? {
                 ['111']: 111 } : {}
             )
-      assert_equal([{}, {111: 111}, {}], ll)
+      assert_equal([{}, {111: 111}, {}], dll)
 
       ll = range(3)
       map(ll, (k, v) => v == 8 || v
@@ -2964,25 +2964,25 @@ def Test_expr7_subscript_linebreak()
   var range = range(
                3)
   var l = range
-       ->map('string(v:key)')
+       ->mapnew('string(v:key)')
   assert_equal(['0', '1', '2'], l)
 
   l = range
-       ->map('string(v:key)')
+       ->mapnew('string(v:key)')
   assert_equal(['0', '1', '2'], l)
 
   l = range # comment
-       ->map('string(v:key)')
+       ->mapnew('string(v:key)')
   assert_equal(['0', '1', '2'], l)
 
   l = range
 
-       ->map('string(v:key)')
+       ->mapnew('string(v:key)')
   assert_equal(['0', '1', '2'], l)
 
   l = range
        # comment
-       ->map('string(v:key)')
+       ->mapnew('string(v:key)')
   assert_equal(['0', '1', '2'], l)
 
   assert_equal('1', l[
index fdad359de00ed8c558134948fdf7bc168a4c54d7..e87c33e909c52d69058bae926c66a89cd4a344ac 100644 (file)
@@ -1763,7 +1763,7 @@ enddef
 
 def Shadowed(): list<number>
   var FuncList: list<func: number> = [() => 42]
-  return FuncList->map((_, Shadowed) => Shadowed())
+  return FuncList->mapnew((_, Shadowed) => Shadowed())
 enddef
 
 def Test_lambda_arg_shadows_func()
@@ -1792,7 +1792,7 @@ enddef
 
 def Line_continuation_in_lambda(): list<string>
   var x = range(97, 100)
-      ->map((_, v) => nr2char(v)
+      ->mapnew((_, v) => nr2char(v)
           ->toupper())
       ->reverse()
   return x
@@ -1908,7 +1908,7 @@ def Test_recursive_call()
 enddef
 
 def TreeWalk(dir: string): list<any>
-  return readdir(dir)->map((_, val) =>
+  return readdir(dir)->mapnew((_, val) =>
             fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
                ? {[val]: TreeWalk(dir .. '/' .. val)}
                : val
index 07c784098882ceb3211fa821a58a29353e72df74..764d09d3f28d25da47b1e74285a874fb5b28fc42 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2325,
 /**/
     2324,
 /**/
index 94f30d4395dcb183727cc59d8c8cdf30f916d18e..bcbc57dd1247c40d464c85c3ac30b18d337987c1 100644 (file)
@@ -1592,6 +1592,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
     garray_T   *stack = &cctx->ctx_type_stack;
     int                argoff;
     type_T     **argtypes = NULL;
+    type_T     *maptype = NULL;
 
     RETURN_OK_IF_SKIP(cctx);
     argoff = check_internal_func(func_idx, argcount);
@@ -1612,6 +1613,8 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
        argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
        if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
            return FAIL;
+       if (internal_func_is_map(func_idx))
+           maptype = *argtypes;
     }
 
     if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
@@ -1627,6 +1630,11 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
                          internal_func_ret_type(func_idx, argcount, argtypes);
     ++stack->ga_len;
 
+    if (maptype != NULL && maptype->tt_member != NULL
+                                              && maptype->tt_member != &t_any)
+       // Check that map() didn't change the item types.
+       generate_TYPECHECK(cctx, maptype, -1);
+
     return OK;
 }