commit 8156eece24134dc26b927d44cd860e44f81cd61c
parent b058a801e7515dd09154f60d7de0219f92635fb8
Author: zeertzjq <zeertzjq@outlook.com>
Date: Mon, 1 Dec 2025 13:45:00 +0800
fix(eval): fix crash with :breakadd expr when calling user func
Diffstat:
2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
@@ -3906,41 +3906,57 @@ funccall_T *get_funccal(void)
return funccal;
}
-/// @return hashtable used for local variables in the current funccal or
+/// @return dict used for local variables in the current funccal or
/// NULL if there is no current funccal.
-hashtab_T *get_funccal_local_ht(void)
+dict_T *get_funccal_local_dict(void)
{
- if (current_funccal == NULL) {
+ if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) {
return NULL;
}
- return &get_funccal()->fc_l_vars.dv_hashtab;
+ return &get_funccal()->fc_l_vars;
+}
+
+/// @return hashtable used for local variables in the current funccal or
+/// NULL if there is no current funccal.
+hashtab_T *get_funccal_local_ht(void)
+{
+ dict_T *d = get_funccal_local_dict();
+ return d != NULL ? &d->dv_hashtab : NULL;
}
/// @return the l: scope variable or
/// NULL if there is no current funccal.
dictitem_T *get_funccal_local_var(void)
{
- if (current_funccal == NULL) {
+ if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) {
return NULL;
}
return (dictitem_T *)&get_funccal()->fc_l_vars_var;
}
-/// @return the hashtable used for argument in the current funccal or
+/// @return the dict used for argument in the current funccal or
/// NULL if there is no current funccal.
-hashtab_T *get_funccal_args_ht(void)
+dict_T *get_funccal_args_dict(void)
{
- if (current_funccal == NULL) {
+ if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) {
return NULL;
}
- return &get_funccal()->fc_l_avars.dv_hashtab;
+ return &get_funccal()->fc_l_avars;
+}
+
+/// @return the hashtable used for argument in the current funccal or
+/// NULL if there is no current funccal.
+hashtab_T *get_funccal_args_ht(void)
+{
+ dict_T *d = get_funccal_args_dict();
+ return d != NULL ? &d->dv_hashtab : NULL;
}
/// @return the a: scope variable or
/// NULL if there is no current funccal.
dictitem_T *get_funccal_args_var(void)
{
- if (current_funccal == NULL) {
+ if (current_funccal == NULL || current_funccal->fc_l_vars.dv_refcount == 0) {
return NULL;
}
return (dictitem_T *)&get_funccal()->fc_l_avars_var;
@@ -3949,7 +3965,7 @@ dictitem_T *get_funccal_args_var(void)
/// List function variables, if there is a function.
void list_func_vars(int *first)
{
- if (current_funccal != NULL) {
+ if (current_funccal != NULL && current_funccal->fc_l_vars.dv_refcount > 0) {
list_hashtable_vars(¤t_funccal->fc_l_vars.dv_hashtab, "l:", false,
first);
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
@@ -2483,7 +2483,6 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va
static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
dict_T **d)
{
- funccall_T *funccal = get_funccal();
*d = NULL;
if (name_len == 0) {
@@ -2503,11 +2502,12 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, cons
return &compat_hashtab;
}
- if (funccal == NULL) { // global variable
- *d = get_globvar_dict();
- } else { // l: variable
- *d = &funccal->fc_l_vars;
+ *d = get_funccal_local_dict();
+ if (*d != NULL) { // local variable
+ goto end;
}
+
+ *d = get_globvar_dict(); // global variable
goto end;
}
@@ -2529,10 +2529,10 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, cons
*d = curtab->tp_vars;
} else if (*name == 'v') { // v: variable
*d = get_vimvar_dict();
- } else if (*name == 'a' && funccal != NULL) { // function argument
- *d = &funccal->fc_l_avars;
- } else if (*name == 'l' && funccal != NULL) { // local variable
- *d = &funccal->fc_l_vars;
+ } else if (*name == 'a') { // a: function argument
+ *d = get_funccal_args_dict();
+ } else if (*name == 'l') { // l: local variable
+ *d = get_funccal_local_dict();
} else if (*name == 's' // script variable
&& (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR
|| current_sctx.sc_sid == SID_LUA)