patch 9.1.1063: too many strlen() calls in userfunc.c

Problem:  too many strlen() calls in userfunc.c
Solution: refactor userfunc.c and remove calls to strlen(),
          drop set_ufunc_name() and roll it into alloc_ufunc(),
          check for out-of-memory condition in trans_function_name_ext()
          (John Marriott)

closes: #16537

Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
John Marriott
2025-02-01 15:25:34 +01:00
committed by Christian Brabandt
parent 3219da514c
commit b32800f7c5
9 changed files with 192 additions and 114 deletions

View File

@ -544,7 +544,7 @@ dict_add_func(dict_T *d, char *key, ufunc_T *fp)
if (item == NULL)
return FAIL;
item->di_tv.v_type = VAR_FUNC;
item->di_tv.vval.v_string = vim_strsave(fp->uf_name);
item->di_tv.vval.v_string = vim_strnsave(fp->uf_name, fp->uf_namelen);
if (dict_add(d, item) == FAIL)
{
dictitem_free(item);

View File

@ -7100,7 +7100,7 @@ handle_subscript(
else
{
rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strsave(ufunc->uf_name);
rettv->vval.v_string = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
}
continue;
}

View File

@ -3135,7 +3135,7 @@ eval_variable(
// assumed.
rettv->vval.v_string = vim_strsave(name);
else
rettv->vval.v_string = vim_strsave(ufunc->uf_name);
rettv->vval.v_string = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
if (rettv->vval.v_string != NULL)
func_ref(ufunc->uf_name);
}

View File

@ -3,6 +3,7 @@ void func_init(void);
hashtab_T *func_tbl_get(void);
char_u *make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize);
char_u *get_lambda_name(void);
size_t get_lambda_name_len(void);
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
int get_lambda_tv(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, type_T **type, int no_autoload, int new_function, int *found_var);

View File

@ -1934,6 +1934,7 @@ struct ufunc_S
char_u *uf_name_exp; // if "uf_name[]" starts with SNR the name with
// "<SNR>" as a string, otherwise NULL
size_t uf_namelen; // length of uf_name (excluding the NUL)
char_u uf_name[4]; // name of function (actual size equals name);
// can start with <SNR>123_ (<SNR> is K_SPECIAL
// KS_EXTRA KE_SNR)

View File

@ -171,9 +171,13 @@ one_function_arg(
if (!skip)
{
if (type == NULL && types_optional)
{
// lambda arguments default to "any" type
type = vim_strsave((char_u *)
(is_vararg ? "list<any>" : "any"));
if (is_vararg)
type = vim_strnsave((char_u *)"list<any>", 9);
else
type = vim_strnsave((char_u *)"any", 3);
}
((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type;
((int8_T *)arg_objm->ga_data)[arg_objm->ga_len++] = FALSE;
}
@ -346,7 +350,7 @@ get_function_args(
if (ga_grow(default_args, 1) == FAIL)
goto err_ret;
char_u *expr = vim_strsave((char_u *)"v:none");
char_u *expr = vim_strnsave((char_u *)"v:none", 6);
if (expr == NULL)
goto err_ret;
((char_u **)(default_args->ga_data))
@ -373,7 +377,7 @@ get_function_args(
{
// TODO: use the actual type
((char_u **)argtypes->ga_data)[argtypes->ga_len++] =
vim_strsave((char_u *)"any");
vim_strnsave((char_u *)"any", 3);
((int8_T *)arg_objm->ga_data)[arg_objm->ga_len++] = TRUE;
// Add a line to the function body for the assignment.
@ -656,24 +660,6 @@ register_closure(ufunc_T *fp)
return OK;
}
static void
set_ufunc_name(ufunc_T *fp, char_u *name)
{
// Add a type cast to avoid a warning for an overflow, the uf_name[] array
// actually extends beyond the struct.
STRCPY((void *)fp->uf_name, name);
if (name[0] == K_SPECIAL)
{
fp->uf_name_exp = alloc(STRLEN(name) + 3);
if (fp->uf_name_exp != NULL)
{
STRCPY(fp->uf_name_exp, "<SNR>");
STRCAT(fp->uf_name_exp, fp->uf_name + 3);
}
}
}
/*
* If "name" starts with K_SPECIAL and "buf[bufsize]" is big enough
* return "buf" filled with a readable function name.
@ -699,14 +685,34 @@ make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize)
/*
* Get a name for a lambda. Returned in static memory.
*/
static char_u lambda_name[8 + NUMBUFLEN];
static size_t lambda_namelen = 0;
char_u *
get_lambda_name(void)
{
static char_u name[30];
static int lambda_no = 0;
static int lambda_no = 0;
int n;
sprintf((char*)name, "<lambda>%d", ++lambda_no);
return name;
n = vim_snprintf((char *)lambda_name, sizeof(lambda_name), "<lambda>%d", ++lambda_no);
if (n < 1)
lambda_namelen = 0;
else
if (n >= (int)sizeof(lambda_name))
lambda_namelen = sizeof(lambda_name) - 1;
else
lambda_namelen = (size_t)n;
return lambda_name;
}
/*
* Get the length of the last lambda name.
*/
size_t
get_lambda_name_len(void)
{
return lambda_namelen;
}
/*
@ -714,12 +720,32 @@ get_lambda_name(void)
* Makes sure the size is right.
*/
static ufunc_T *
alloc_ufunc(char_u *name)
alloc_ufunc(char_u *name, size_t namelen)
{
size_t len;
ufunc_T *fp;
// When the name is short we need to make sure we allocate enough bytes for
// the whole struct, including any padding.
size_t len = offsetof(ufunc_T, uf_name) + STRLEN(name) + 1;
return alloc_clear(len < sizeof(ufunc_T) ? sizeof(ufunc_T) : len);
len = offsetof(ufunc_T, uf_name) + namelen + 1;
fp = alloc_clear(len < sizeof(ufunc_T) ? sizeof(ufunc_T) : len);
if (fp != NULL)
{
// Add a type cast to avoid a warning for an overflow, the uf_name[] array
// can actually extend beyond the struct.
STRCPY((void *)fp->uf_name, name);
fp->uf_namelen = namelen;
if (name[0] == K_SPECIAL)
{
len = namelen + 3; // including +1 for NUL
fp->uf_name_exp = alloc(len);
if (fp->uf_name_exp != NULL)
vim_snprintf((char *)fp->uf_name_exp, len, "<SNR>%s", fp->uf_name + 3);
}
}
return fp;
}
#if defined(FEAT_LUA) || defined(PROTO)
@ -731,9 +757,10 @@ alloc_ufunc(char_u *name)
register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
{
char_u *name = get_lambda_name();
size_t namelen = get_lambda_name_len();
ufunc_T *fp;
fp = alloc_ufunc(name);
fp = alloc_ufunc(name, namelen);
if (fp == NULL)
return NULL;
@ -747,7 +774,6 @@ register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
fp->uf_cb_free = cb_free;
fp->uf_cb_state = state;
set_ufunc_name(fp, name);
hash_add(&func_hashtab, UF2HIKEY(fp), "add C function");
return name;
@ -976,6 +1002,7 @@ get_function_body(
int heredoc_concat_len = 0;
garray_T heredoc_ga;
char_u *heredoc_trimmed = NULL;
size_t heredoc_trimmedlen = 0;
ga_init2(&heredoc_ga, 1, 500);
@ -1059,19 +1086,20 @@ get_function_body(
if (heredoc_trimmed == NULL
|| (is_heredoc && skipwhite(theline) == theline)
|| STRNCMP(theline, heredoc_trimmed,
STRLEN(heredoc_trimmed)) == 0)
heredoc_trimmedlen) == 0)
{
if (heredoc_trimmed == NULL)
p = theline;
else if (is_heredoc)
p = skipwhite(theline) == theline
? theline : theline + STRLEN(heredoc_trimmed);
? theline : theline + heredoc_trimmedlen;
else
p = theline + STRLEN(heredoc_trimmed);
p = theline + heredoc_trimmedlen;
if (STRCMP(p, skip_until) == 0)
{
VIM_CLEAR(skip_until);
VIM_CLEAR(heredoc_trimmed);
heredoc_trimmedlen = 0;
getline_options = vim9_function
? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT;
is_heredoc = FALSE;
@ -1271,7 +1299,7 @@ get_function_body(
|| (p[2] == 's'
&& (!ASCII_ISALPHA(p[3])
|| p[3] == 'e'))))))))
skip_until = vim_strsave((char_u *)".");
skip_until = vim_strnsave((char_u *)".", 1);
// Check for ":python <<EOF", ":tcl <<EOF", etc.
arg = skipwhite(skiptowhite(p));
@ -1298,11 +1326,13 @@ get_function_body(
{
// Ignore leading white space.
p = skipwhite(p + 4);
heredoc_trimmed = vim_strnsave(theline,
skipwhite(theline) - theline);
heredoc_trimmedlen = skipwhite(theline) - theline;
heredoc_trimmed = vim_strnsave(theline, heredoc_trimmedlen);
if (heredoc_trimmed == NULL)
heredoc_trimmedlen = 0;
}
if (*p == NUL)
skip_until = vim_strsave((char_u *)".");
skip_until = vim_strnsave((char_u *)".", 1);
else
skip_until = vim_strnsave(p, skiptowhite(p) - p);
getline_options = GETLINE_NONE;
@ -1344,8 +1374,10 @@ get_function_body(
{
// Ignore leading white space.
p = skipwhite(p + 4);
heredoc_trimmed = vim_strnsave(theline,
skipwhite(theline) - theline);
heredoc_trimmedlen = skipwhite(theline) - theline;
heredoc_trimmed = vim_strnsave(theline, heredoc_trimmedlen);
if (heredoc_trimmed == NULL)
heredoc_trimmedlen = 0;
continue;
}
if (STRNCMP(p, "eval", 4) == 0)
@ -1374,7 +1406,7 @@ get_function_body(
// to be used for the instruction later.
ga_concat(&heredoc_ga, theline);
ga_concat(&heredoc_ga, (char_u *)"\n");
p = vim_strsave((char_u *)"");
p = vim_strnsave((char_u *)"", 0);
}
else
{
@ -1437,6 +1469,7 @@ lambda_function_body(
int ret = FAIL;
partial_T *pt;
char_u *name;
size_t namelen;
int lnum_save = -1;
linenr_T sourcing_lnum_top = SOURCING_LNUM;
char_u *line_arg = NULL;
@ -1498,8 +1531,12 @@ lambda_function_body(
// Insert NL characters at the start of each line, the string will
// be split again later in .get_lambda_tv().
if (*p == NUL || vim9_comment_start(p))
{
p = (char_u *)"";
plen = STRLEN(p);
plen = 0;
}
else
plen = STRLEN(p);
pnl = vim_strnsave((char_u *)"\n", plen + 1);
if (pnl != NULL)
mch_memmove(pnl + 1, p, plen + 1);
@ -1509,12 +1546,17 @@ lambda_function_body(
if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
goto erret;
if (eap.nextcmd != NULL)
{
// more is following after the "}", which was skipped
last = cmdline;
plen = STRLEN(last);
}
else
{
// nothing is following the "}"
last = (char_u *)"}";
plen = STRLEN(last);
plen = 1;
}
pnl = vim_strnsave((char_u *)"\n", plen + 1);
if (pnl != NULL)
mch_memmove(pnl + 1, last, plen + 1);
@ -1546,10 +1588,10 @@ lambda_function_body(
}
name = get_lambda_name();
ufunc = alloc_ufunc(name);
namelen = get_lambda_name_len();
ufunc = alloc_ufunc(name, namelen);
if (ufunc == NULL)
goto erret;
set_ufunc_name(ufunc, name);
if (hash_add(&func_hashtab, UF2HIKEY(ufunc), "add function") == FAIL)
goto erret;
ufunc->uf_flags = FC_LAMBDA;
@ -1755,8 +1797,9 @@ get_lambda_tv(
char_u *p;
char_u *line_end;
char_u *name = get_lambda_name();
size_t namelen = get_lambda_name_len();
fp = alloc_ufunc(name);
fp = alloc_ufunc(name, namelen);
if (fp == NULL)
goto errret;
fp->uf_def_status = UF_NOT_COMPILED;
@ -1804,7 +1847,6 @@ get_lambda_tv(
flags |= FC_NOARGS;
fp->uf_refcount = 1;
set_ufunc_name(fp, name);
fp->uf_args = newargs;
ga_init(&fp->uf_def_args);
if (types_optional)
@ -1875,10 +1917,13 @@ errret:
{
ga_clear_strings(&argtypes);
ga_clear(&arg_objm);
if (fp != NULL)
vim_free(fp->uf_arg_types);
}
vim_free(fp);
if (fp != NULL)
{
vim_free(fp->uf_arg_types);
vim_free(fp->uf_name_exp);
vim_free(fp);
}
vim_free(pt);
vim_free(tofree2);
eval_lavars_used = old_eval_lavars;
@ -2184,44 +2229,48 @@ fname_trans_sid(
char_u **tofree,
funcerror_T *error)
{
int llen;
char_u *script_name;
char_u *fname;
int i;
size_t fnamelen;
size_t fname_buflen;
llen = eval_fname_script(name);
if (llen == 0)
script_name = name + eval_fname_script(name);
if (script_name == name)
return name; // no prefix
fname_buf[0] = K_SPECIAL;
fname_buf[1] = KS_EXTRA;
fname_buf[2] = (int)KE_SNR;
i = 3;
if (eval_fname_sid(name)) // "<SID>" or "s:"
fname_buflen = 3;
if (!eval_fname_sid(name)) // "<SID>" or "s:"
fname_buf[fname_buflen] = NUL;
else
{
if (current_sctx.sc_sid <= 0)
*error = FCERR_SCRIPT;
else
{
sprintf((char *)fname_buf + 3, "%ld_",
fname_buflen += vim_snprintf((char *)fname_buf + 3,
FLEN_FIXED - 3,
"%ld_",
(long)current_sctx.sc_sid);
i = (int)STRLEN(fname_buf);
}
}
if (i + STRLEN(name + llen) < FLEN_FIXED)
fnamelen = fname_buflen + STRLEN(script_name);
if (fnamelen < FLEN_FIXED)
{
STRCPY(fname_buf + i, name + llen);
STRCPY(fname_buf + fname_buflen, script_name);
fname = fname_buf;
}
else
{
fname = alloc(i + STRLEN(name + llen) + 1);
fname = alloc(fnamelen + 1);
if (fname == NULL)
*error = FCERR_OTHER;
else
{
*tofree = fname;
mch_memmove(fname, fname_buf, (size_t)i);
STRCPY(fname + i, name + llen);
vim_snprintf((char *)fname, fnamelen + 1, "%s%s", fname_buf, script_name);
}
}
return fname;
@ -2391,7 +2440,7 @@ func_is_global(ufunc_T *ufunc)
int
func_requires_g_prefix(ufunc_T *ufunc)
{
return ufunc->uf_name[0] != K_SPECIAL
return func_is_global(ufunc)
&& (ufunc->uf_flags & FC_LAMBDA) == 0
&& vim_strchr(ufunc->uf_name, AUTOLOAD_CHAR) == NULL
&& !SAFE_isdigit(ufunc->uf_name[0]);
@ -2402,16 +2451,17 @@ func_requires_g_prefix(ufunc_T *ufunc)
* "buf" must be able to hold the function name plus three bytes.
* Takes care of script-local function names.
*/
static void
cat_func_name(char_u *buf, ufunc_T *fp)
static int
cat_func_name(char_u *buf, size_t bufsize, ufunc_T *fp)
{
int len;
if (!func_is_global(fp))
{
STRCPY(buf, "<SNR>");
STRCAT(buf, fp->uf_name + 3);
}
len = vim_snprintf((char *)buf, bufsize, "<SNR>%s", fp->uf_name + 3);
else
STRCPY(buf, fp->uf_name);
len = vim_snprintf((char *)buf, bufsize, "%s", fp->uf_name);
return (len >= (int)bufsize) ? (int)bufsize - 1 : len;
}
/*
@ -2773,7 +2823,7 @@ copy_lambda_to_global_func(
return FAIL;
}
fp = alloc_ufunc(global);
fp = alloc_ufunc(global, STRLEN(global));
if (fp == NULL)
return FAIL;
@ -2805,9 +2855,6 @@ copy_lambda_to_global_func(
fp->uf_refcount = 1;
fp->uf_name_exp = NULL;
set_ufunc_name(fp, global);
hash_add(&func_hashtab, UF2HIKEY(fp), "copy lambda");
// the referenced dfunc_T is now used one more time
@ -2943,6 +2990,7 @@ call_user_func(
int islambda = FALSE;
char_u numbuf[NUMBUFLEN];
char_u *name;
size_t namelen;
typval_T *tv_to_free[MAX_FUNC_ARGS];
int tv_to_free_len = 0;
#ifdef FEAT_PROFILE
@ -3099,6 +3147,8 @@ call_user_func(
break;
}
}
namelen = STRLEN(name);
}
else
{
@ -3107,10 +3157,10 @@ call_user_func(
break;
// "..." argument a:1, a:2, etc.
sprintf((char *)numbuf, "%d", ai + 1);
namelen = vim_snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1);
name = numbuf;
}
if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN)
if (fixvar_idx < FIXVAR_CNT && namelen <= VAR_SHORT_LEN)
{
v = &fc->fc_fixvar[fixvar_idx++].var;
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
@ -3491,8 +3541,7 @@ delete_script_functions(int sid)
buf[0] = K_SPECIAL;
buf[1] = KS_EXTRA;
buf[2] = (int)KE_SNR;
sprintf((char *)buf + 3, "%d_", sid);
len = STRLEN(buf);
len = 3 + vim_snprintf((char *)buf + 3, sizeof(buf) - 3, "%d_", sid);
while (todo > 0)
{
@ -4388,7 +4437,7 @@ trans_function_name_ext(
{
if (ufunc != NULL)
*ufunc = lv.ll_ufunc;
name = vim_strsave(lv.ll_ufunc->uf_name);
name = vim_strnsave(lv.ll_ufunc->uf_name, lv.ll_ufunc->uf_namelen);
*pp = end;
goto theend;
}
@ -4485,7 +4534,7 @@ trans_function_name_ext(
{
name = vim_strsave(name);
*pp = end;
if (STRNCMP(name, "<SNR>", 5) == 0)
if (name != NULL && STRNCMP(name, "<SNR>", 5) == 0)
{
// Change "<SNR>" to the byte sequence.
name[0] = K_SPECIAL;
@ -4567,17 +4616,19 @@ trans_function_name_ext(
&& eval_fname_sid(lv.ll_exp_name))
|| eval_fname_sid(*pp))
{
size_t sid_buflen;
// It's script-local, "s:" or "<SID>"
if (current_sctx.sc_sid <= 0)
{
emsg(_(e_using_sid_not_in_script_context));
goto theend;
}
sprintf((char *)sid_buf, "%ld_", (long)current_sctx.sc_sid);
sid_buflen = vim_snprintf((char *)sid_buf, sizeof(sid_buf), "%ld_", (long)current_sctx.sc_sid);
if (vim9_local)
extra = 3 + (int)STRLEN(sid_buf);
extra = 3 + (int)sid_buflen;
else
lead += (int)STRLEN(sid_buf);
lead += (int)sid_buflen;
}
}
// The function name must start with an upper case letter (unless it is a
@ -4664,8 +4715,10 @@ untrans_function_name(char_u *name)
get_scriptlocal_funcname(char_u *funcname)
{
char sid_buf[25];
size_t sid_buflen;
int off;
char_u *newname;
size_t newnamesize;
char_u *p = funcname;
if (funcname == NULL)
@ -4696,13 +4749,13 @@ get_scriptlocal_funcname(char_u *funcname)
return NULL;
}
// Expand s: prefix into <SNR>nr_<name>
vim_snprintf(sid_buf, sizeof(sid_buf), "<SNR>%ld_",
sid_buflen = vim_snprintf(sid_buf, sizeof(sid_buf), "<SNR>%ld_",
(long)current_sctx.sc_sid);
newname = alloc(STRLEN(sid_buf) + STRLEN(p + off) + 1);
newnamesize = sid_buflen + STRLEN(p + off) + 1;
newname = alloc(newnamesize);
if (newname == NULL)
return NULL;
STRCPY(newname, sid_buf);
STRCAT(newname, p + off);
vim_snprintf((char *)newname, newnamesize, "%s%s", sid_buf, p + off);
return newname;
}
@ -4811,6 +4864,7 @@ define_function(
int c;
int saved_did_emsg = FALSE;
char_u *name = name_arg;
size_t namelen = 0;
int is_global = FALSE;
char_u *p;
char_u *arg;
@ -5107,7 +5161,7 @@ define_function(
// In Vim9 script a function cannot have the same name as a
// variable.
if (vim9script && *arg == K_SPECIAL
&& eval_variable(name_base, (int)STRLEN(name_base), 0, NULL,
&& eval_variable(name_base, i, 0, NULL,
NULL, EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT
+ EVAL_VAR_NO_FUNC) == OK)
{
@ -5252,7 +5306,7 @@ define_function(
*/
if (fudi.fd_dict != NULL)
{
char numbuf[20];
char numbuf[NUMBUFLEN];
fp = NULL;
if (fudi.fd_newkey == NULL && !eap->forceit)
@ -5273,8 +5327,8 @@ define_function(
// Give the function a sequential number. Can only be used with a
// Funcref!
vim_free(name);
sprintf(numbuf, "%d", ++func_nr);
name = vim_strsave((char_u *)numbuf);
namelen = vim_snprintf(numbuf, sizeof(numbuf), "%d", ++func_nr);
name = vim_strnsave((char_u *)numbuf, namelen);
if (name == NULL)
goto erret;
}
@ -5373,6 +5427,7 @@ define_function(
// redefine existing function, keep the expanded name
VIM_CLEAR(name);
namelen = 0;
fp->uf_name_exp = NULL;
func_clear_items(fp);
fp->uf_name_exp = exp_name;
@ -5421,7 +5476,9 @@ define_function(
}
}
fp = alloc_ufunc(name);
if (namelen == 0)
namelen = STRLEN(name);
fp = alloc_ufunc(name, namelen);
if (fp == NULL)
goto erret;
fp_allocated = TRUE;
@ -5448,7 +5505,7 @@ define_function(
// overwrite existing dict entry
clear_tv(&fudi.fd_di->di_tv);
fudi.fd_di->di_tv.v_type = VAR_FUNC;
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
fudi.fd_di->di_tv.vval.v_string = vim_strnsave(name, namelen);
// behave like "dict" was used
flags |= FC_DICT;
@ -5506,7 +5563,6 @@ define_function(
if (fp_allocated)
{
// insert the new function in the function list
set_ufunc_name(fp, name);
if (overwrite)
{
hi = hash_find(&func_hashtab, name);
@ -5581,6 +5637,7 @@ errret_2:
{
VIM_CLEAR(fp->uf_arg_types);
VIM_CLEAR(fp->uf_va_name);
VIM_CLEAR(fp->uf_name_exp);
clear_func_type_list(&fp->uf_type_list, &fp->uf_func_type);
}
if (free_fp)
@ -5918,6 +5975,8 @@ get_user_func_name(expand_T *xp, int idx)
}
if (changed == func_hashtab.ht_changed && done < func_hashtab.ht_used)
{
int len;
if (done++ > 0)
++hi;
while (HASHITEM_EMPTY(hi))
@ -5929,16 +5988,19 @@ get_user_func_name(expand_T *xp, int idx)
|| STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
return (char_u *)"";
if (STRLEN(fp->uf_name) + 4 >= IOSIZE)
if (fp->uf_namelen + 4 >= IOSIZE)
return fp->uf_name; // prevents overflow
cat_func_name(IObuff, fp);
len = cat_func_name(IObuff, IOSIZE, fp);
if (xp->xp_context != EXPAND_USER_FUNC
&& xp->xp_context != EXPAND_DISASSEMBLE)
{
STRCAT(IObuff, "(");
STRCPY(IObuff + len, "(");
if (!has_varargs(fp) && fp->uf_args.ga_len == 0)
STRCAT(IObuff, ")");
{
++len;
STRCPY(IObuff + len, ")");
}
}
return IObuff;
}
@ -5955,7 +6017,7 @@ get_user_func_name(expand_T *xp, int idx)
ufunc_T *
copy_function(ufunc_T *fp)
{
ufunc_T *ufunc = alloc_ufunc(fp->uf_name);
ufunc_T *ufunc = alloc_ufunc(fp->uf_name, fp->uf_namelen);
if (ufunc == NULL)
return NULL;
@ -6004,8 +6066,6 @@ copy_function(ufunc_T *fp)
ga_copy_strings(&fp->uf_lines, &ufunc->uf_lines);
ufunc->uf_refcount = 1;
ufunc->uf_name_exp = NULL;
STRCPY(ufunc->uf_name, fp->uf_name);
return ufunc;
}
@ -6760,20 +6820,31 @@ discard_pending_return(void *rettv)
get_return_cmd(void *rettv)
{
char_u *s = NULL;
char_u *tofree = NULL;
char_u numbuf[NUMBUFLEN];
size_t slen = 0;
size_t IObufflen;
if (rettv != NULL)
{
char_u *tofree = NULL;
char_u numbuf[NUMBUFLEN];
s = echo_string((typval_T *)rettv, &tofree, numbuf, 0);
vim_free(tofree);
}
if (s == NULL)
s = (char_u *)"";
else
slen = STRLEN(s);
STRCPY(IObuff, ":return ");
STRNCPY(IObuff + 8, s, IOSIZE - 8);
if (STRLEN(s) + 8 >= IOSIZE)
IObufflen = 8 + slen;
if (slen + 8 >= IOSIZE)
{
STRCPY(IObuff + IOSIZE - 4, "...");
vim_free(tofree);
return vim_strsave(IObuff);
IObufflen += 3;
}
return vim_strnsave(IObuff, IObufflen);
}
/*

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1063,
/**/
1062,
/**/

View File

@ -1034,6 +1034,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free)
int off;
char_u *func_name;
char_u *lambda_name;
size_t lambda_namelen;
ufunc_T *ufunc;
int r = FAIL;
compiletype_T compile_type;
@ -1092,7 +1093,9 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free)
eap->forceit = FALSE;
// We use the special <Lamba>99 name, but it's not really a lambda.
lambda_name = vim_strsave(get_lambda_name());
lambda_name = get_lambda_name();
lambda_namelen = get_lambda_name_len();
lambda_name = vim_strnsave(lambda_name, lambda_namelen);
if (lambda_name == NULL)
return NULL;
@ -3884,7 +3887,7 @@ add_def_function(ufunc_T *ufunc)
dfunc->df_idx = def_functions.ga_len;
ufunc->uf_dfunc_idx = dfunc->df_idx;
dfunc->df_ufunc = ufunc;
dfunc->df_name = vim_strsave(ufunc->uf_name);
dfunc->df_name = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
ga_init2(&dfunc->df_var_names, sizeof(char_u *), 10);
++dfunc->df_refcount;
++def_functions.ga_len;

View File

@ -1445,7 +1445,7 @@ generate_FUNCREF(
}
}
if (ufunc->uf_def_status == UF_NOT_COMPILED || cl != NULL)
extra->fre_func_name = vim_strsave(ufunc->uf_name);
extra->fre_func_name = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
if (ufunc->uf_def_status != UF_NOT_COMPILED && cl == NULL)
{
if (isn_idx == NULL && ufunc->uf_def_status == UF_TO_BE_COMPILED)
@ -1912,7 +1912,7 @@ generate_CALL(
{
// A user function may be deleted and redefined later, can't use the
// ufunc pointer, need to look it up again at runtime.
isn->isn_arg.ufunc.cuf_name = vim_strsave(ufunc->uf_name);
isn->isn_arg.ufunc.cuf_name = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
isn->isn_arg.ufunc.cuf_argcount = argcount;
}