]> granicus.if.org Git - vim/commitdiff
patch 9.0.0990: callback name argument is changed by setqflist() v9.0.0990
authorBram Moolenaar <Bram@vim.org>
Fri, 2 Dec 2022 15:58:38 +0000 (15:58 +0000)
committerBram Moolenaar <Bram@vim.org>
Fri, 2 Dec 2022 15:58:38 +0000 (15:58 +0000)
Problem:    Callback name argument is changed by setqflist().
Solution:   Use the expanded function name for the callback, do not store it
            in the argument. (closes #11653)

src/change.c
src/evalvars.c
src/job.c
src/option.c
src/popupwin.c
src/quickfix.c
src/testdir/test_quickfix.vim
src/time.c
src/version.c

index 7796d292077687847bfe78be5377d77579c1ad57..dc68d3cf7c0ba97b8b4f81cf2bdfec500c0a0a83 100644 (file)
@@ -259,6 +259,8 @@ f_listener_add(typval_T *argvars, typval_T *rettv)
     buf->b_listener = lnr;
 
     set_callback(&lnr->lr_callback, &callback);
+    if (callback.cb_free_name)
+       vim_free(callback.cb_name);
 
     lnr->lr_id = ++next_listener_id;
     rettv->vval.v_number = lnr->lr_id;
index 20223c8fe8d40867ea9189b68b4461cdc378167c..31cc760bf09703e619698439a0970dec8621d151 100644 (file)
@@ -4792,9 +4792,9 @@ f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
 
 /*
  * Get a callback from "arg".  It can be a Funcref or a function name.
- * When "arg" is zero return an empty string.
- * "cb_name" is not allocated.
- * "cb_name" is set to NULL for an invalid argument.
+ * When "arg" is zero "res.cb_name" is set to an empty string.
+ * If "res.cb_name" is allocated then "res.cb_free_name" is set to TRUE.
+ * "res.cb_name" is set to NULL for an invalid argument.
  */
     callback_T
 get_callback(typval_T *arg)
@@ -4802,7 +4802,7 @@ get_callback(typval_T *arg)
     callback_T  res;
     int                r = OK;
 
-    res.cb_free_name = FALSE;
+    CLEAR_FIELD(res);
     if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
     {
        res.cb_partial = arg->vval.v_partial;
@@ -4811,25 +4811,21 @@ get_callback(typval_T *arg)
     }
     else
     {
-       res.cb_partial = NULL;
        if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
                                               && isdigit(*arg->vval.v_string))
            r = FAIL;
        else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
        {
+           res.cb_name = arg->vval.v_string;
            if (arg->v_type == VAR_STRING)
            {
-               char_u *name;
-
-               name = get_scriptlocal_funcname(arg->vval.v_string);
+               char_u *name = get_scriptlocal_funcname(arg->vval.v_string);
                if (name != NULL)
                {
-                   vim_free(arg->vval.v_string);
-                   arg->vval.v_string = name;
+                   res.cb_name = name;
+                   res.cb_free_name = TRUE;
                }
            }
-
-           res.cb_name = arg->vval.v_string;
            func_ref(res.cb_name);
        }
        else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
index 259d49c3d080248f0a387c27fb481ff9f0c5a4f5..ba5eec0f10b4baad7a0a95b73126972c767cd81a 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -74,32 +74,31 @@ clear_job_options(jobopt_T *opt)
     CLEAR_POINTER(opt);
 }
 
+    static void
+unref_job_callback(callback_T *cb)
+{
+    if (cb->cb_partial != NULL)
+       partial_unref(cb->cb_partial);
+    else if (cb->cb_name != NULL)
+    {
+       func_unref(cb->cb_name);
+       if (cb->cb_free_name)
+           vim_free(cb->cb_name);
+    }
+}
+
 /*
  * Free any members of a jobopt_T.
  */
     void
 free_job_options(jobopt_T *opt)
 {
-    if (opt->jo_callback.cb_partial != NULL)
-       partial_unref(opt->jo_callback.cb_partial);
-    else if (opt->jo_callback.cb_name != NULL)
-       func_unref(opt->jo_callback.cb_name);
-    if (opt->jo_out_cb.cb_partial != NULL)
-       partial_unref(opt->jo_out_cb.cb_partial);
-    else if (opt->jo_out_cb.cb_name != NULL)
-       func_unref(opt->jo_out_cb.cb_name);
-    if (opt->jo_err_cb.cb_partial != NULL)
-       partial_unref(opt->jo_err_cb.cb_partial);
-    else if (opt->jo_err_cb.cb_name != NULL)
-       func_unref(opt->jo_err_cb.cb_name);
-    if (opt->jo_close_cb.cb_partial != NULL)
-       partial_unref(opt->jo_close_cb.cb_partial);
-    else if (opt->jo_close_cb.cb_name != NULL)
-       func_unref(opt->jo_close_cb.cb_name);
-    if (opt->jo_exit_cb.cb_partial != NULL)
-       partial_unref(opt->jo_exit_cb.cb_partial);
-    else if (opt->jo_exit_cb.cb_name != NULL)
-       func_unref(opt->jo_exit_cb.cb_name);
+    unref_job_callback(&opt->jo_callback);
+    unref_job_callback(&opt->jo_out_cb);
+    unref_job_callback(&opt->jo_err_cb);
+    unref_job_callback(&opt->jo_close_cb);
+    unref_job_callback(&opt->jo_exit_cb);
+
     if (opt->jo_env != NULL)
        dict_unref(opt->jo_env);
 }
@@ -1687,6 +1686,8 @@ f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
 
     free_callback(&buf->b_prompt_callback);
     set_callback(&buf->b_prompt_callback, &callback);
+    if (callback.cb_free_name)
+       vim_free(callback.cb_name);
 }
 
 /*
@@ -1714,6 +1715,8 @@ f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
 
     free_callback(&buf->b_prompt_interrupt);
     set_callback(&buf->b_prompt_interrupt, &callback);
+    if (callback.cb_free_name)
+       vim_free(callback.cb_name);
 }
 
 
index 816837d0af75f8928d9e1eb6703540bf4638fba3..07a9e52f3aa998078b3e660c174b901b244fb9ad 100644 (file)
@@ -7370,6 +7370,8 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
 
     free_callback(optcb);
     set_callback(optcb, &cb);
+    if (cb.cb_free_name)
+       vim_free(cb.cb_name);
     free_tv(tv);
 
     // when using Vim9 style "import.funcname" it needs to be expanded to
index 9bc31746ec031ac99285f1d2064ed405bae67b06..e487f0c225d86f310eae05e44f60b7b698d90914 100644 (file)
@@ -444,7 +444,13 @@ popup_add_timeout(win_T *wp, int time, int close)
     if (get_lambda_tv_and_compile(&ptr, &tv, FALSE, &EVALARG_EVALUATE) == OK)
     {
        wp->w_popup_timer = create_timer(time, 0);
-       wp->w_popup_timer->tr_callback = get_callback(&tv);
+       callback_T cb = get_callback(&tv);
+       if (cb.cb_name != NULL && !cb.cb_free_name)
+       {
+           cb.cb_name = vim_strsave(cb.cb_name);
+           cb.cb_free_name = TRUE;
+       }
+       wp->w_popup_timer->tr_callback = cb;
        clear_tv(&tv);
     }
 }
@@ -961,6 +967,8 @@ apply_general_options(win_T *wp, dict_T *dict)
        {
            free_callback(&wp->w_filter_cb);
            set_callback(&wp->w_filter_cb, &callback);
+           if (callback.cb_free_name)
+               vim_free(callback.cb_name);
        }
     }
     nr = dict_get_bool(dict, "mapping", -1);
@@ -990,6 +998,8 @@ apply_general_options(win_T *wp, dict_T *dict)
        {
            free_callback(&wp->w_close_cb);
            set_callback(&wp->w_close_cb, &callback);
+           if (callback.cb_free_name)
+               vim_free(callback.cb_name);
        }
     }
 }
@@ -2229,7 +2239,11 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
        tv.vval.v_string = (char_u *)"popup_filter_menu";
        callback = get_callback(&tv);
        if (callback.cb_name != NULL)
+       {
            set_callback(&wp->w_filter_cb, &callback);
+           if (callback.cb_free_name)
+               vim_free(callback.cb_name);
+       }
 
        wp->w_p_wrap = 0;
        wp->w_popup_flags |= POPF_CURSORLINE;
index 4c414e0ad90a2949f54a2b34a974dd3e11308e5d..ca5b35652ceaa6decf99fdc2e1dfc05415aac12f 100644 (file)
@@ -7633,7 +7633,11 @@ qf_setprop_qftf(qf_info_T *qi UNUSED, qf_list_T *qfl, dictitem_T *di)
     free_callback(&qfl->qf_qftf_cb);
     cb = get_callback(&di->di_tv);
     if (cb.cb_name != NULL && *cb.cb_name != NUL)
+    {
        set_callback(&qfl->qf_qftf_cb, &cb);
+       if (cb.cb_free_name)
+           vim_free(cb.cb_name);
+    }
 
     return OK;
 }
index e82e64757d5414353fbd2d0bfde07bbb8d04cd74..1620db5281a44a6e927d498aa9c58b3299728e06 100644 (file)
@@ -6387,5 +6387,17 @@ func Test_info_line_with_space()
   call setqflist([], 'f')
 endfunc
 
+func s:QfTf(_)
+endfunc
+
+func Test_setqflist_cb_arg()
+  " This was changing the callback name in the dictionary.
+  let d = #{quickfixtextfunc: 's:QfTf'}
+  call setqflist([], 'a', d)
+  call assert_equal('s:QfTf', d.quickfixtextfunc)
+
+  call setqflist([], 'f')
+endfunc
+
 
 " vim: shiftwidth=2 sts=2 expandtab
index 891a9f49edde23e15772db48d52a53f6240017b0..efdad690a475c49bd3f6f50d7c684962c212cbb6 100644 (file)
@@ -908,6 +908,8 @@ f_timer_start(typval_T *argvars, typval_T *rettv)
     else
     {
        set_callback(&timer->tr_callback, &callback);
+       if (callback.cb_free_name)
+           vim_free(callback.cb_name);
        rettv->vval.v_number = (varnumber_T)timer->tr_id;
     }
 }
index 6583d462a1127bcb345003d26ea170bbb6d3bd5f..f9b1e6c220f7a2ac6d6422d767324116d1a711b6 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    990,
 /**/
     989,
 /**/