vim-patch:8.2.0633: crash when using null partial in filter()

Problem:    Crash when using null partial in filter().
Solution:   Fix crash.  Add more tests. (Yegappan Lakshmanan, closes vim/vim#5976)

9d8d0b5c64

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-04-15 13:17:32 +08:00
parent 3d80392cab
commit 4b49f312a0
8 changed files with 88 additions and 17 deletions

View File

@ -789,6 +789,9 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *r
}
} else if (expr->v_type == VAR_PARTIAL) {
partial_T *const partial = expr->vval.v_partial;
if (partial == NULL) {
return FAIL;
}
const char *const s = partial_name(partial);
if (s == NULL || *s == NUL) {
return FAIL;
@ -8640,8 +8643,9 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic)
}
if ((typ1->v_type == VAR_PARTIAL && typ1->vval.v_partial == NULL)
|| (typ2->v_type == VAR_PARTIAL && typ2->vval.v_partial == NULL)) {
// when a partial is NULL assume not equal
n1 = false;
// When both partials are NULL, then they are equal.
// Otherwise they are not equal.
n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
} else if (type_is) {
if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) {
// strings are considered the same if their value is

View File

@ -205,7 +205,7 @@ func Test_vvar_scriptversion1()
call assert_equal(511, 0o777)
endfunc
func Test_excute_null()
func Test_execute_cmd_with_null()
call assert_fails('execute v:_null_list', 'E730:')
call assert_fails('execute v:_null_dict', 'E731:')
call assert_fails('execute v:_null_blob', 'E976:')

View File

@ -170,7 +170,7 @@ func Test_win_execute_visual_redraw()
bwipe!
endfunc
func Test_execute_null()
func Test_execute_cmd_with_null()
call assert_equal("", execute(v:_null_string))
call assert_equal("", execute(v:_null_list))
call assert_fails('call execute(v:_null_dict)', 'E731:')

View File

@ -22,6 +22,9 @@ func Test_equal()
call assert_false([base.method] == [instance.other])
call assert_fails('echo base.method > instance.method')
" Nvim doesn't have null functions
" call assert_equal(0, test_null_function() == function('min'))
" call assert_equal(1, test_null_function() == test_null_function())
endfunc
func Test_version()
@ -712,4 +715,24 @@ func Test_expr_eval_error()
call assert_fails("let v = -{}", 'E728:')
endfunc
" Test for float value comparison
func Test_float_compare()
CheckFeature float
call assert_true(1.2 == 1.2)
call assert_true(1.0 != 1.2)
call assert_true(1.2 > 1.0)
call assert_true(1.2 >= 1.2)
call assert_true(1.0 < 1.2)
call assert_true(1.2 <= 1.2)
call assert_true(+0.0 == -0.0)
" two NaNs (not a number) are not equal
call assert_true(sqrt(-4.01) != (0.0 / 0.0))
" two inf (infinity) are equal
call assert_true((1.0 / 0) == (2.0 / 0))
" two -inf (infinity) are equal
call assert_true(-(1.0 / 0) == -(2.0 / 0))
" +infinity != -infinity
call assert_true((1.0 / 0) != -(2.0 / 0))
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -93,6 +93,12 @@ func Test_map_filter_fails()
call assert_equal(v:_null_dict, filter(v:_null_dict, 0))
call assert_equal(v:_null_list, map(v:_null_list, '"> " .. v:val'))
call assert_equal(v:_null_dict, map(v:_null_dict, '"> " .. v:val'))
" Nvim doesn't have null functions
" call assert_equal([1, 2, 3], filter([1, 2, 3], test_null_function()))
call assert_fails("let l = filter([1, 2], function('min'))", 'E118:')
" Nvim doesn't have null partials
" call assert_equal([1, 2, 3], filter([1, 2, 3], test_null_partial()))
call assert_fails("let l = filter([1, 2], {a, b, c -> 1})", 'E119:')
endfunc
func Test_map_and_modify()

View File

@ -85,6 +85,24 @@ func Test_let()
let l:Test_Local_Var = {'k' : 5}
call assert_match("\nl:Test_Local_Var {'k': 5}", execute('let l:'))
call assert_match("v:errors []", execute('let v:'))
" Test for assigning multiple list items
let l = [1, 2, 3]
let [l[0], l[1]] = [10, 20]
call assert_equal([10, 20, 3], l)
" Test for errors in conditional expression
call assert_fails('let val = [] ? 1 : 2', 'E745:')
call assert_fails('let val = 1 ? 5+ : 6', 'E121:')
call assert_fails('let val = 1 ? 0 : 5+', 'E15:')
call assert_false(exists('val'))
" Test for errors in logical operators
let @a = 'if [] || 0 | let val = 2 | endif'
call assert_fails('exe @a', 'E745:')
call assert_fails('call feedkeys(":let val = 0 || []\<cr>", "xt")', 'E745:')
call assert_fails('exe "let val = [] && 5"', 'E745:')
call assert_fails('exe "let val = 6 && []"', 'E745:')
endfunc
func s:set_arg1(a) abort

View File

@ -1081,6 +1081,7 @@ func Test_null_dict()
call assert_equal('{}', string(d))
call assert_fails('let x = v:_null_dict[10]')
call assert_equal({}, {})
call assert_equal(0, len(copy(d)))
endfunc
" Test for the indexof() function

View File

@ -63,16 +63,18 @@ endfunc
func Test_partial_dict()
let dict = {'name': 'hello'}
let Cb = function('MyDictFunc', ["foo", "bar"], dict)
call test_garbagecollect_now()
call assert_equal("hello/foo/bar", Cb())
call assert_fails('Cb("xxx")', 'E492:')
let Cb = function('MyDictFunc', ["foo"], dict)
call assert_equal("hello/foo/xxx", Cb("xxx"))
call assert_fails('Cb()', 'E492:')
let Cb = function('MyDictFunc', [], dict)
call assert_equal("hello/ttt/xxx", Cb("ttt", "xxx"))
call assert_fails('Cb("yyy")', 'E492:')
let Cb = function('MyDictFunc', ["foo"], dict)
call assert_equal("hello/foo/xxx", Cb("xxx"))
call assert_fails('Cb()', 'E492:')
let Cb = function('MyDictFunc', dict)
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
call assert_fails('Cb("fff")', 'E492:')
@ -238,17 +240,22 @@ endfunc
func Ignored(job1, job2, status)
endfunc
" func Test_cycle_partial_job()
" let job = job_start('echo')
" call job_setoptions(job, {'exit_cb': function('Ignored', [job])})
" unlet job
" endfunc
func Test_cycle_partial_job()
if has('job')
let job = job_start('echo')
call job_setoptions(job, {'exit_cb': function('Ignored', [job])})
unlet job
endif
endfunc
" func Test_ref_job_partial_dict()
" let g:ref_job = job_start('echo')
" let d = {'a': 'b'}
" call job_setoptions(g:ref_job, {'exit_cb': function('string', [], d)})
" endfunc
func Test_ref_job_partial_dict()
if has('job')
let g:ref_job = job_start('echo')
let d = {'a': 'b'}
call job_setoptions(g:ref_job, {'exit_cb': function('string', [], d)})
call test_garbagecollect_now()
endif
endfunc
func Test_auto_partial_rebind()
let dict1 = {'name': 'dict1'}
@ -356,6 +363,18 @@ func Test_compare_partials()
call assert_true(F1 isnot# F2) " Different functions
call assert_true(F1 isnot# F1d1) " Partial /= non-partial
call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time
" compare two null partials
" Nvim doesn't have null partials
" let N1 = test_null_partial()
let N1 = function('min')
let N2 = N1
call assert_true(N1 is N2)
call assert_true(N1 == N2)
" compare a partial and a null partial
call assert_false(N1 == F1)
call assert_false(F1 is N1)
endfunc
" vim: shiftwidth=2 sts=2 expandtab