]> granicus.if.org Git - vim/commitdiff
patch 8.2.3756: might crash when callback is not valid v8.2.3756
authorYegappan Lakshmanan <yegappan@yahoo.com>
Tue, 7 Dec 2021 12:23:57 +0000 (12:23 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 7 Dec 2021 12:23:57 +0000 (12:23 +0000)
Problem:    might crash when callback is not valid.
Solution:   Check for valid callback. (Yegappan Lakshmanan, closes #9293)

src/insexpand.c
src/job.c
src/option.c
src/tag.c
src/testdir/test_iminsert.vim
src/testdir/test_ins_complete.vim
src/testdir/test_tagfunc.vim
src/userfunc.c
src/version.c

index 92f0731eb54a6238eccb0577bbf7e4a7f6d6e0f3..8c09841f00e6ed9a05b6ec4aa7ca1bbe9369e4a1 100644 (file)
@@ -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);
     }
 
index ebe902fb04ce2bd90465ac09c2d57b39a0d565d7..6ee9f4432e817ef5cc4182e107988a9fbaf73292 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -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;
 }
 
 /*
index 8d950b1770a203a672aea402ffbfaff927d88ce4..bfe8f57b5212f27da93150ccd93ec6da9a23f6c7 100644 (file)
@@ -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;
index f932934769357b6dbb750496cdf4520e6c909a3e..41d21b7514ceaea2d90d73ac56227c82385cec1e 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -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;
index c3c4725a1e528db19763679b1c508e6f38778465..a53e6f36b485a556c2f6ce4455886007051f0db6 100644 (file)
@@ -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
index d508ba087f6e65351c8e62ce6be14ef6f65aced5..aa7b24bf85b2a15d8942f4ad303679730289e768 100644 (file)
@@ -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&
index 7f16fb25e573640e0705411b71f893b8154b40d6..b9139d4ffcae5d15a7dfb321d68705e4b198efa2 100644 (file)
@@ -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
index 4f86c07910bf3f978f74a82a2b242907ec30c205..4423ae59a5b836d43dc128cabfc028ffc1c78454 100644 (file)
@@ -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);
index 294547b8626c5e3486189e6bab1deff596d84a89..c586acbd2ff94ca98e48a310f676ff11d4c2dab4 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3756,
 /**/
     3755,
 /**/