vim-patch:8.2.1083: crash when using reduce() on a NULL list

Problem:    Crash when using reduce() on a NULL list.
Solution:   Only access the list when not NULL.
fda20c4cc5

CHECK_LIST_MATERIALIZE hasn't been ported yet, but presumably if it is ported
it'll use tv_list_first to check for range_list_item, which already checks for
NULL, so this should need no extra changes and can be a full port.

We didn't actually crash here due to the use of Nvim's tv_list functions
checking for NULL, but apply these changes to match Vim better anyway.
This commit is contained in:
Sean Dewar 2021-12-06 22:51:08 +00:00 committed by zeertzjq
parent 44a5875b24
commit 8d99f53f3d
2 changed files with 19 additions and 13 deletions

View File

@ -7901,22 +7901,25 @@ static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr)
li = tv_list_first(l);
}
const VarLockStatus prev_locked = tv_list_locked(l);
const int called_emsg_start = called_emsg;
tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here
tv_copy(&initial, rettv);
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
argv[0] = *rettv;
argv[1] = *TV_LIST_ITEM_TV(li);
rettv->v_type = VAR_UNKNOWN;
const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start) {
break;
if (l != NULL) {
const VarLockStatus prev_locked = tv_list_locked(l);
const int called_emsg_start = called_emsg;
tv_list_set_lock(l, VAR_FIXED); // disallow the list changing here
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
argv[0] = *rettv;
argv[1] = *TV_LIST_ITEM_TV(li);
rettv->v_type = VAR_UNKNOWN;
const int r = call_func(func_name, -1, rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start) {
break;
}
}
tv_list_set_lock(l, prev_locked);
}
tv_list_set_lock(l, prev_locked);
} else {
const blob_T *const b = argvars[0].vval.v_blob;
int i;

View File

@ -658,6 +658,9 @@ func Test_reduce()
call assert_fails("call reduce(g:lut, { acc, val -> EvilRemove() }, 1)", 'E742:')
unlet g:lut
delfunc EvilRemove
call assert_equal(42, reduce(v:_null_list, function('add'), 42))
call assert_equal(42, reduce(v:_null_blob, function('add'), 42))
endfunc
" splitting a string to a List