To: vim_dev@googlegroups.com Subject: Patch 8.2.3756 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3756 Problem: might crash when callback is not valid. Solution: Check for valid callback. (Yegappan Lakshmanan, closes #9293) Files: src/insexpand.c, src/option.c, src/tag.c, src/job.c, src/userfunc.c, src/testdir/test_iminsert.vim, src/testdir/test_ins_complete.vim, src/testdir/test_tagfunc.vim *** ../vim-8.2.3755/src/insexpand.c 2021-12-03 11:08:34.256842709 +0000 --- src/insexpand.c 2021-12-07 12:20:34.468477441 +0000 *************** *** 2329,2342 **** 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); } --- 2329,2340 ---- *** ../vim-8.2.3755/src/option.c 2021-12-06 11:03:50.950900210 +0000 --- src/option.c 2021-12-07 12:10:17.382513874 +0000 *************** *** 7210,7216 **** return FAIL; cb = get_callback(tv); ! if (cb.cb_name == NULL) { free_tv(tv); return FAIL; --- 7210,7216 ---- return FAIL; cb = get_callback(tv); ! if (cb.cb_name == NULL || *cb.cb_name == NUL) { free_tv(tv); return FAIL; *** ../vim-8.2.3755/src/tag.c 2021-12-05 21:46:31.172891155 +0000 --- src/tag.c 2021-12-07 12:21:44.312138332 +0000 *************** *** 1361,1367 **** dict_T *d; taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx]; ! if (*curbuf->b_p_tfu == NUL) return FAIL; args[0].v_type = VAR_STRING; --- 1361,1368 ---- dict_T *d; taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx]; ! 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; *** ../vim-8.2.3755/src/job.c 2021-12-05 22:19:22.832153464 +0000 --- src/job.c 2021-12-07 12:23:45.155602075 +0000 *************** *** 1578,1583 **** --- 1578,1584 ---- { 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,1593 **** argv[0].v_type = VAR_UNKNOWN; got_int = FALSE; // don't skip executing commands ! call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv); clear_tv(&rettv); ! return TRUE; } /* --- 1586,1594 ---- argv[0].v_type = VAR_UNKNOWN; got_int = FALSE; // don't skip executing commands ! ret = call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv); clear_tv(&rettv); ! return ret == FAIL ? FALSE : TRUE; } /* *** ../vim-8.2.3755/src/userfunc.c 2021-12-06 15:06:49.335517805 +0000 --- src/userfunc.c 2021-12-07 12:19:37.004775284 +0000 *************** *** 3146,3151 **** --- 3146,3152 ---- /* * Invoke call_func() with a callback. + * Returns FAIL if the callback could not be called. */ int call_callback( *************** *** 3159,3164 **** --- 3160,3167 ---- 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,3176 **** /* * 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] * for the function arguments. argv[argc] should have type VAR_UNKNOWN. */ varnumber_T --- 3173,3179 ---- /* * call the 'callback' function and return the result as a number. ! * 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,3190 **** varnumber_T retval; if (call_callback(callback, 0, &rettv, argcount, argvars) == FAIL) ! return -1; retval = tv_get_number_chk(&rettv, NULL); clear_tv(&rettv); --- 3187,3193 ---- varnumber_T retval; if (call_callback(callback, 0, &rettv, argcount, argvars) == FAIL) ! return -2; retval = tv_get_number_chk(&rettv, NULL); clear_tv(&rettv); *** ../vim-8.2.3755/src/testdir/test_iminsert.vim 2021-12-06 11:03:50.954900203 +0000 --- src/testdir/test_iminsert.vim 2021-12-07 12:10:17.382513874 +0000 *************** *** 257,262 **** --- 257,275 ---- 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 *** ../vim-8.2.3755/src/testdir/test_ins_complete.vim 2021-12-06 11:03:50.954900203 +0000 --- src/testdir/test_ins_complete.vim 2021-12-07 12:10:17.382513874 +0000 *************** *** 1074,1079 **** --- 1074,1088 ---- call assert_fails('call feedkeys("A\\\", "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\\\", 'x') + call assert_equal([[1, ''], [0, 'five']], g:MycompleteFunc2_args) + " cleanup delfunc MycompleteFunc1 delfunc MycompleteFunc2 *************** *** 1285,1290 **** --- 1294,1308 ---- call assert_fails('call feedkeys("A\\\", "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\\\", 'x') + call assert_equal([[1, ''], [0, 'nine']], g:MyomniFunc2_args) + " cleanup delfunc MyomniFunc1 delfunc MyomniFunc2 *************** *** 1522,1527 **** --- 1540,1555 ---- call feedkeys("A\\\", "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\\\", 'x') + call assert_equal([[1, ''], [0, 'ten']], g:MytsrFunc2_args) " cleanup set thesaurusfunc& *** ../vim-8.2.3755/src/testdir/test_tagfunc.vim 2021-12-06 11:03:50.954900203 +0000 --- src/testdir/test_tagfunc.vim 2021-12-07 12:10:17.382513874 +0000 *************** *** 317,322 **** --- 317,327 ---- 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 *** ../vim-8.2.3755/src/version.c 2021-12-07 11:03:35.260224997 +0000 --- src/version.c 2021-12-07 12:12:12.602367161 +0000 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 3756, /**/ -- All good vision statements are created by groups of people with bloated bladders who would rather be doing anything else. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///