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

Commit: 
https://github.com/vim/vim/commit/b32800f7c51c866dc0e87244eb4902540982309d
Author: John Marriott <basil...@internode.on.net>
Date:   Sat Feb 1 15:25:34 2025 +0100

    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 <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/dict.c b/src/dict.c
index 8f0db7edc..7975904da 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -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);
diff --git a/src/eval.c b/src/eval.c
index 387f61d87..9a140c166 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
        }
diff --git a/src/evalvars.c b/src/evalvars.c
index e0ca4b81d..1b11f2847 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -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);
                }
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index cdcf017d3..a0f04b206 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -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);
diff --git a/src/structs.h b/src/structs.h
index 69494dd9b..7c51c72bd 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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)
diff --git a/src/userfunc.c b/src/userfunc.c
index 91c971e8f..81f1f284e 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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 *)"
");
-           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 *)"
", 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 *)"
", 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);
 }
 
 /*
diff --git a/src/version.c b/src/version.c
index d59ce56b7..e785b4228 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1063,
 /**/
     1062,
 /**/
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 29b6414c4..aa3e17ef6 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 4368e3c2d..b51903950 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -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;
     }
 

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1teEVX-00GOhG-OX%40256bit.org.

Raspunde prin e-mail lui