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>
diff --git a/src/userfunc.c b/src/userfunc.c
index 91c971e..81f1f28 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -171,9 +171,13 @@
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 @@
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 @@
{
// 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 @@
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 @@
/*
* 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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
|| (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 @@
{
// 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 @@
{
// 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 @@
// 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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
* "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 @@
return FAIL;
}
- fp = alloc_ufunc(global);
+ fp = alloc_ufunc(global, STRLEN(global));
if (fp == NULL)
return FAIL;
@@ -2805,9 +2855,6 @@
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 @@
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 @@
break;
}
}
+
+ namelen = STRLEN(name);
}
else
{
@@ -3107,10 +3157,10 @@
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 @@
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 @@
{
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 @@
{
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 @@
&& 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 @@
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 @@
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 @@
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 @@
// 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 @@
*/
if (fudi.fd_dict != NULL)
{
- char numbuf[20];
+ char numbuf[NUMBUFLEN];
fp = NULL;
if (fudi.fd_newkey == NULL && !eap->forceit)
@@ -5273,8 +5327,8 @@
// 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 @@
// 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 @@
}
}
- 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 @@
// 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 @@
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 @@
{
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 @@
}
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 @@
|| 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 @@
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 @@
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 @@
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);
}
/*