Skip to content

Commit 75ab91f

Browse files
committed
patch 8.2.2325: Vim9: crash if map() changes the item type
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.
1 parent 6f02b00 commit 75ab91f

8 files changed

Lines changed: 50 additions & 18 deletions

File tree

src/evalfunc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,15 @@ internal_func_ret_type(int idx, int argcount, type_T **argtypes)
19291929
return global_functions[idx].f_retfunc(argcount, argtypes);
19301930
}
19311931

1932+
/*
1933+
* Return TRUE if "idx" is for the map() function.
1934+
*/
1935+
int
1936+
internal_func_is_map(int idx)
1937+
{
1938+
return global_functions[idx].f_func == f_map;
1939+
}
1940+
19321941
/*
19331942
* Check the argument count to use for internal function "idx".
19341943
* Returns -1 for failure, 0 if no method base accepted, 1 if method base is

src/list.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,10 +2188,13 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
21882188
int stride = l->lv_u.nonmat.lv_stride;
21892189

21902190
// List from range(): loop over the numbers
2191-
l->lv_first = NULL;
2192-
l->lv_u.mat.lv_last = NULL;
2193-
l->lv_len = 0;
2194-
l->lv_u.mat.lv_idx_item = NULL;
2191+
if (filtermap != FILTERMAP_MAPNEW)
2192+
{
2193+
l->lv_first = NULL;
2194+
l->lv_u.mat.lv_last = NULL;
2195+
l->lv_len = 0;
2196+
l->lv_u.mat.lv_idx_item = NULL;
2197+
}
21952198

21962199
for (idx = 0; idx < len; ++idx)
21972200
{

src/proto/evalfunc.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ int has_internal_func(char_u *name);
66
char *internal_func_name(int idx);
77
int internal_func_check_arg_types(type_T **types, int idx, int argcount);
88
type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
9+
int internal_func_is_map(int idx);
910
int check_internal_func(int idx, int argcount);
1011
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
1112
void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv);

src/testdir/test_vim9_builtin.vim

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def Test_extend_arg_types()
231231
assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, s:string_keep))
232232

233233
var res: list<dict<any>>
234-
extend(res, map([1, 2], (_, v) => ({})))
234+
extend(res, mapnew([1, 2], (_, v) => ({})))
235235
assert_equal([{}, {}], res)
236236

237237
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()
320320
CheckDefAndScriptSuccess(lines)
321321
enddef
322322

323+
def Test_map_item_type()
324+
var lines =<< trim END
325+
var l = ['a', 'b', 'c']
326+
map(l, (k, v) => k .. '/' .. v )
327+
assert_equal(['0/a', '1/b', '2/c'], l)
328+
END
329+
CheckDefAndScriptSuccess(lines)
330+
enddef
331+
323332
def Test_filereadable()
324333
assert_false(filereadable(""))
325334
assert_false(filereadable(test_null_string()))
@@ -728,7 +737,7 @@ enddef
728737

729738
def Test_submatch()
730739
var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
731-
var Rep = () => range(10)->map((_, v) => submatch(v, true))->string()
740+
var Rep = () => range(10)->mapnew((_, v) => submatch(v, true))->string()
732741
var actual = substitute('A123456789', pat, Rep, '')
733742
var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]"
734743
actual->assert_equal(expected)

src/testdir/test_vim9_expr.vim

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,10 +1859,10 @@ def Test_expr7_lambda()
18591859

18601860
# line continuation inside lambda with "cond ? expr : expr" works
18611861
var ll = range(3)
1862-
map(ll, (k, v) => v % 2 ? {
1862+
var dll = mapnew(ll, (k, v) => v % 2 ? {
18631863
['111']: 111 } : {}
18641864
)
1865-
assert_equal([{}, {111: 111}, {}], ll)
1865+
assert_equal([{}, {111: 111}, {}], dll)
18661866

18671867
ll = range(3)
18681868
map(ll, (k, v) => v == 8 || v
@@ -1946,10 +1946,10 @@ def Test_expr7_new_lambda()
19461946

19471947
# line continuation inside lambda with "cond ? expr : expr" works
19481948
var ll = range(3)
1949-
map(ll, (k, v) => v % 2 ? {
1949+
var dll = mapnew(ll, (k, v) => v % 2 ? {
19501950
['111']: 111 } : {}
19511951
)
1952-
assert_equal([{}, {111: 111}, {}], ll)
1952+
assert_equal([{}, {111: 111}, {}], dll)
19531953

19541954
ll = range(3)
19551955
map(ll, (k, v) => v == 8 || v
@@ -2964,25 +2964,25 @@ def Test_expr7_subscript_linebreak()
29642964
var range = range(
29652965
3)
29662966
var l = range
2967-
->map('string(v:key)')
2967+
->mapnew('string(v:key)')
29682968
assert_equal(['0', '1', '2'], l)
29692969

29702970
l = range
2971-
->map('string(v:key)')
2971+
->mapnew('string(v:key)')
29722972
assert_equal(['0', '1', '2'], l)
29732973

29742974
l = range # comment
2975-
->map('string(v:key)')
2975+
->mapnew('string(v:key)')
29762976
assert_equal(['0', '1', '2'], l)
29772977

29782978
l = range
29792979

2980-
->map('string(v:key)')
2980+
->mapnew('string(v:key)')
29812981
assert_equal(['0', '1', '2'], l)
29822982

29832983
l = range
29842984
# comment
2985-
->map('string(v:key)')
2985+
->mapnew('string(v:key)')
29862986
assert_equal(['0', '1', '2'], l)
29872987

29882988
assert_equal('1', l[

src/testdir/test_vim9_func.vim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,7 +1763,7 @@ enddef
17631763

17641764
def Shadowed(): list<number>
17651765
var FuncList: list<func: number> = [() => 42]
1766-
return FuncList->map((_, Shadowed) => Shadowed())
1766+
return FuncList->mapnew((_, Shadowed) => Shadowed())
17671767
enddef
17681768

17691769
def Test_lambda_arg_shadows_func()
@@ -1792,7 +1792,7 @@ enddef
17921792

17931793
def Line_continuation_in_lambda(): list<string>
17941794
var x = range(97, 100)
1795-
->map((_, v) => nr2char(v)
1795+
->mapnew((_, v) => nr2char(v)
17961796
->toupper())
17971797
->reverse()
17981798
return x
@@ -1908,7 +1908,7 @@ def Test_recursive_call()
19081908
enddef
19091909

19101910
def TreeWalk(dir: string): list<any>
1911-
return readdir(dir)->map((_, val) =>
1911+
return readdir(dir)->mapnew((_, val) =>
19121912
fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
19131913
? {[val]: TreeWalk(dir .. '/' .. val)}
19141914
: val

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2325,
753755
/**/
754756
2324,
755757
/**/

src/vim9compile.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
15921592
garray_T *stack = &cctx->ctx_type_stack;
15931593
int argoff;
15941594
type_T **argtypes = NULL;
1595+
type_T *maptype = NULL;
15951596

15961597
RETURN_OK_IF_SKIP(cctx);
15971598
argoff = check_internal_func(func_idx, argcount);
@@ -1612,6 +1613,8 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
16121613
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
16131614
if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
16141615
return FAIL;
1616+
if (internal_func_is_map(func_idx))
1617+
maptype = *argtypes;
16151618
}
16161619

16171620
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)
16271630
internal_func_ret_type(func_idx, argcount, argtypes);
16281631
++stack->ga_len;
16291632

1633+
if (maptype != NULL && maptype->tt_member != NULL
1634+
&& maptype->tt_member != &t_any)
1635+
// Check that map() didn't change the item types.
1636+
generate_TYPECHECK(cctx, maptype, -1);
1637+
16301638
return OK;
16311639
}
16321640

0 commit comments

Comments
 (0)