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)
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;
/*
* 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)
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;
}
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)
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);
}
free_callback(&buf->b_prompt_callback);
set_callback(&buf->b_prompt_callback, &callback);
+ if (callback.cb_free_name)
+ vim_free(callback.cb_name);
}
/*
free_callback(&buf->b_prompt_interrupt);
set_callback(&buf->b_prompt_interrupt, &callback);
+ if (callback.cb_free_name)
+ vim_free(callback.cb_name);
}
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
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);
}
}
{
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);
{
free_callback(&wp->w_close_cb);
set_callback(&wp->w_close_cb, &callback);
+ if (callback.cb_free_name)
+ vim_free(callback.cb_name);
}
}
}
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;
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;
}
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
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;
}
}
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 990,
/**/
989,
/**/