0
0
mirror of https://github.com/vim/vim.git synced 2025-09-28 04:24:06 -04:00

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) if (item == NULL)
return FAIL; return FAIL;
item->di_tv.v_type = VAR_FUNC; 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) if (dict_add(d, item) == FAIL)
{ {
dictitem_free(item); dictitem_free(item);

View File

@@ -7100,7 +7100,7 @@ handle_subscript(
else else
{ {
rettv->v_type = VAR_FUNC; 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; continue;
} }

View File

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

View File

@@ -3,6 +3,7 @@ void func_init(void);
hashtab_T *func_tbl_get(void); hashtab_T *func_tbl_get(void);
char_u *make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize); char_u *make_ufunc_name_readable(char_u *name, char_u *buf, size_t bufsize);
char_u *get_lambda_name(void); 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); 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); 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); 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 char_u *uf_name_exp; // if "uf_name[]" starts with SNR the name with
// "<SNR>" as a string, otherwise NULL // "<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); char_u uf_name[4]; // name of function (actual size equals name);
// can start with <SNR>123_ (<SNR> is K_SPECIAL // can start with <SNR>123_ (<SNR> is K_SPECIAL
// KS_EXTRA KE_SNR) // KS_EXTRA KE_SNR)

View File

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

View File

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

View File

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

View File

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