# HG changeset patch # User Bram Moolenaar # Date 1639570503 -3600 # Node ID ba52a5ef59f1a76809d1c6dd6a6ad76426a330b7 # Parent 7e742336d4bdda308d6b9f8a1fd205df2e27458f patch 8.2.3812: Vim9: leaking memory in numbered function test Commit: https://github.com/vim/vim/commit/57bc2333b1d713bc54f8e33ef3ef7ac169af2ac4 Author: Bram Moolenaar Date: Wed Dec 15 12:06:43 2021 +0000 patch 8.2.3812: Vim9: leaking memory in numbered function test Problem: Vim9: leaking memory in numbered function test. Solution: Skip "g:" when checking for numbered function. Clean up after errors properly. diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2136,6 +2136,16 @@ cleanup_function_call(funccall_T *fc) } /* + * Return TRUE if "name" is a numbered function, ignoring a "g:" prefix. + */ + static int +numbered_function(char_u *name) +{ + return isdigit(*name) + || (name[0] == 'g' && name[1] == ':' && isdigit(name[2])); +} + +/* * There are two kinds of function names: * 1. ordinary names, function defined with :function or :def * 2. numbered functions and lambdas @@ -2146,7 +2156,7 @@ cleanup_function_call(funccall_T *fc) int func_name_refcount(char_u *name) { - return isdigit(*name) || *name == '<'; + return numbered_function(name) || *name == '<'; } /* @@ -3956,6 +3966,8 @@ define_function(exarg_T *eap, char_u *na int flags = 0; char_u *ret_type = NULL; ufunc_T *fp = NULL; + int fp_allocated = FALSE; + int free_fp = FALSE; int overwrite = FALSE; dictitem_T *v; funcdict_T fudi; @@ -4460,6 +4472,7 @@ define_function(exarg_T *eap, char_u *na fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (fp == NULL) goto erret; + fp_allocated = TRUE; if (fudi.fd_dict != NULL) { @@ -4490,21 +4503,6 @@ define_function(exarg_T *eap, char_u *na // behave like "dict" was used flags |= FC_DICT; } - - // insert the new function in the function list - set_ufunc_name(fp, name); - if (overwrite) - { - hi = hash_find(&func_hashtab, name); - hi->hi_key = UF2HIKEY(fp); - } - else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) - { - vim_free(fp); - fp = NULL; - goto erret; - } - fp->uf_refcount = 1; } fp->uf_args = newargs; fp->uf_def_args = default_args; @@ -4527,7 +4525,8 @@ define_function(exarg_T *eap, char_u *na if (parse_argument_types(fp, &argtypes, varargs) == FAIL) { SOURCING_LNUM = lnum_save; - goto errret_2; + free_fp = fp_allocated; + goto erret; } varargs = FALSE; @@ -4535,6 +4534,7 @@ define_function(exarg_T *eap, char_u *na if (parse_return_type(fp, ret_type) == FAIL) { SOURCING_LNUM = lnum_save; + free_fp = fp_allocated; goto erret; } SOURCING_LNUM = lnum_save; @@ -4542,7 +4542,25 @@ define_function(exarg_T *eap, char_u *na else fp->uf_def_status = UF_NOT_COMPILED; + if (fp_allocated) + { + // insert the new function in the function list + set_ufunc_name(fp, name); + if (overwrite) + { + hi = hash_find(&func_hashtab, name); + hi->hi_key = UF2HIKEY(fp); + } + else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) + { + free_fp = TRUE; + goto erret; + } + fp->uf_refcount = 1; + } + fp->uf_lines = newlines; + newlines.ga_data = NULL; if ((flags & FC_CLOSURE) != 0) { if (register_closure(fp) == FAIL) @@ -4593,6 +4611,11 @@ errret_2: ga_clear_strings(&newlines); if (fp != NULL) VIM_CLEAR(fp->uf_arg_types); + if (free_fp) + { + vim_free(fp); + fp = NULL; + } ret_free: ga_clear_strings(&argtypes); vim_free(line_to_free); @@ -4813,7 +4836,7 @@ ex_delfunction(exarg_T *eap) if (eap->nextcmd != NULL) *p = NUL; - if (isdigit(*name) && fudi.fd_dict == NULL) + if (numbered_function(name) && fudi.fd_dict == NULL) { if (!eap->skip) semsg(_(e_invarg2), eap->arg); @@ -4881,7 +4904,7 @@ func_unref(char_u *name) if (name == NULL || !func_name_refcount(name)) return; fp = find_func(name, FALSE, NULL); - if (fp == NULL && isdigit(*name)) + if (fp == NULL && numbered_function(name)) { #ifdef EXITFREE if (!entered_free_all_mem) @@ -4924,7 +4947,7 @@ func_ref(char_u *name) fp = find_func(name, FALSE, NULL); if (fp != NULL) ++fp->uf_refcount; - else if (isdigit(*name)) + else if (numbered_function(name)) // Only give an error for a numbered function. // Fail silently, when named or lambda function isn't found. internal_error("func_ref()"); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3812, +/**/ 3811, /**/ 3810,