diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2021-12-07 12:23:57 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-12-07 12:23:57 +0000 |
commit | 4dc24eb5adbcc76838fae1e900936dd230209d96 (patch) | |
tree | 79f8deb9ac0294b4cbc228cbde0180ce205964c7 | |
parent | 92c33eb2735045d25fceed3b607f44d7156c59c1 (diff) | |
download | vim-git-4dc24eb5adbcc76838fae1e900936dd230209d96.tar.gz |
patch 8.2.3756: might crash when callback is not validv8.2.3756
Problem: might crash when callback is not valid.
Solution: Check for valid callback. (Yegappan Lakshmanan, closes #9293)
-rw-r--r-- | src/insexpand.c | 2 | ||||
-rw-r--r-- | src/job.c | 5 | ||||
-rw-r--r-- | src/option.c | 2 | ||||
-rw-r--r-- | src/tag.c | 3 | ||||
-rw-r--r-- | src/testdir/test_iminsert.vim | 13 | ||||
-rw-r--r-- | src/testdir/test_ins_complete.vim | 28 | ||||
-rw-r--r-- | src/testdir/test_tagfunc.vim | 5 | ||||
-rw-r--r-- | src/userfunc.c | 7 | ||||
-rw-r--r-- | src/version.c | 2 |
9 files changed, 59 insertions, 8 deletions
diff --git a/src/insexpand.c b/src/insexpand.c index 92f0731eb..8c09841f0 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2329,14 +2329,12 @@ set_thesaurusfunc_option(void) if (*curbuf->b_p_tsrfu != NUL) { // buffer-local option set - free_callback(&curbuf->b_tsrfu_cb); retval = option_set_callback_func(curbuf->b_p_tsrfu, &curbuf->b_tsrfu_cb); } else { // global option set - free_callback(&tsrfu_cb); retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); } @@ -1578,6 +1578,7 @@ invoke_prompt_interrupt(void) { typval_T rettv; typval_T argv[1]; + int ret; if (curbuf->b_prompt_interrupt.cb_name == NULL || *curbuf->b_prompt_interrupt.cb_name == NUL) @@ -1585,9 +1586,9 @@ invoke_prompt_interrupt(void) argv[0].v_type = VAR_UNKNOWN; got_int = FALSE; // don't skip executing commands - call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv); + ret = call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv); clear_tv(&rettv); - return TRUE; + return ret == FAIL ? FALSE : TRUE; } /* diff --git a/src/option.c b/src/option.c index 8d950b177..bfe8f57b5 100644 --- a/src/option.c +++ b/src/option.c @@ -7210,7 +7210,7 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED) return FAIL; cb = get_callback(tv); - if (cb.cb_name == NULL) + if (cb.cb_name == NULL || *cb.cb_name == NUL) { free_tv(tv); return FAIL; @@ -1361,7 +1361,8 @@ find_tagfunc_tags( dict_T *d; taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx]; - if (*curbuf->b_p_tfu == NUL) + if (*curbuf->b_p_tfu == NUL || curbuf->b_tfu_cb.cb_name == NULL + || *curbuf->b_tfu_cb.cb_name == NUL) return FAIL; args[0].v_type = VAR_STRING; diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim index c3c4725a1..a53e6f36b 100644 --- a/src/testdir/test_iminsert.vim +++ b/src/testdir/test_iminsert.vim @@ -257,6 +257,19 @@ func Test_imactivatefunc_imstatusfunc_callback() set imstatusfunc=()\ =>\ IMstatusfunc1(a) call assert_fails('normal! i', 'E117:') + " set 'imactivatefunc' and 'imstatusfunc' to a non-existing function + set imactivatefunc=IMactivatefunc1 + set imstatusfunc=IMstatusfunc1 + call assert_fails("set imactivatefunc=function('NonExistingFunc')", 'E700:') + call assert_fails("set imstatusfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("let &imactivatefunc = function('NonExistingFunc')", 'E700:') + call assert_fails("let &imstatusfunc = function('NonExistingFunc')", 'E700:') + let g:IMactivatefunc_called = 0 + let g:IMstatusfunc_called = 0 + normal! i + call assert_equal(2, g:IMactivatefunc_called) + call assert_equal(2, g:IMstatusfunc_called) + " cleanup delfunc IMactivatefunc1 delfunc IMstatusfunc1 diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index d508ba087..aa7b24bf8 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -1074,6 +1074,15 @@ func Test_completefunc_callback() call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:') call assert_equal([], g:MycompleteFunc2_args) + " set 'completefunc' to a non-existing function + set completefunc=MycompleteFunc2 + call setline(1, 'five') + call assert_fails("set completefunc=function('NonExistingFunc')", 'E700:') + call assert_fails("let &completefunc = function('NonExistingFunc')", 'E700:') + let g:MycompleteFunc2_args = [] + call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'five']], g:MycompleteFunc2_args) + " cleanup delfunc MycompleteFunc1 delfunc MycompleteFunc2 @@ -1285,6 +1294,15 @@ func Test_omnifunc_callback() call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:') call assert_equal([], g:MyomniFunc2_args) + " set 'omnifunc' to a non-existing function + set omnifunc=MyomniFunc2 + call setline(1, 'nine') + call assert_fails("set omnifunc=function('NonExistingFunc')", 'E700:') + call assert_fails("let &omnifunc = function('NonExistingFunc')", 'E700:') + let g:MyomniFunc2_args = [] + call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'nine']], g:MyomniFunc2_args) + " cleanup delfunc MyomniFunc1 delfunc MyomniFunc2 @@ -1522,6 +1540,16 @@ func Test_thesaurusfunc_callback() call feedkeys("A\<C-X>\<C-T>\<Esc>", "x") call assert_equal('sunday', getline(1)) call assert_equal([[1, ''], [0, 'sun']], g:MytsrFunc4_args) + %bw! + + " set 'thesaurusfunc' to a non-existing function + set thesaurusfunc=MytsrFunc2 + call setline(1, 'ten') + call assert_fails("set thesaurusfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("let &thesaurusfunc = function('NonExistingFunc')", 'E700:') + let g:MytsrFunc2_args = [] + call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'ten']], g:MytsrFunc2_args) " cleanup set thesaurusfunc& diff --git a/src/testdir/test_tagfunc.vim b/src/testdir/test_tagfunc.vim index 7f16fb25e..b9139d4ff 100644 --- a/src/testdir/test_tagfunc.vim +++ b/src/testdir/test_tagfunc.vim @@ -317,6 +317,11 @@ func Test_tagfunc_callback() call assert_fails("tag a17", "E117:") call assert_equal([], g:MytagFunc3_args) + " set 'tagfunc' to a non-existing function + call assert_fails("set tagfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("let &tagfunc = function('NonExistingFunc')", 'E700:') + call assert_fails("tag axb123", 'E426:') + " cleanup delfunc MytagFunc1 delfunc MytagFunc2 diff --git a/src/userfunc.c b/src/userfunc.c index 4f86c0791..4423ae59a 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3146,6 +3146,7 @@ get_callback_depth(void) /* * Invoke call_func() with a callback. + * Returns FAIL if the callback could not be called. */ int call_callback( @@ -3159,6 +3160,8 @@ call_callback( funcexe_T funcexe; int ret; + if (callback->cb_name == NULL || *callback->cb_name == NUL) + return FAIL; CLEAR_FIELD(funcexe); funcexe.evaluate = TRUE; funcexe.partial = callback->cb_partial; @@ -3170,7 +3173,7 @@ call_callback( /* * call the 'callback' function and return the result as a number. - * Returns -1 when calling the function fails. Uses argv[0] to argv[argc - 1] + * Returns -2 when calling the function fails. Uses argv[0] to argv[argc - 1] * for the function arguments. argv[argc] should have type VAR_UNKNOWN. */ varnumber_T @@ -3184,7 +3187,7 @@ call_callback_retnr( varnumber_T retval; if (call_callback(callback, 0, &rettv, argcount, argvars) == FAIL) - return -1; + return -2; retval = tv_get_number_chk(&rettv, NULL); clear_tv(&rettv); diff --git a/src/version.c b/src/version.c index 294547b86..c586acbd2 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3756, +/**/ 3755, /**/ 3754, |