From 4d7dfa081be59bc8f66eb0d1a4ddfd7c1748f72c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 4 Apr 2026 09:20:38 +0800 Subject: [PATCH] vim-patch:9.2.0291: too many strlen() calls Problem: too many strlen() calls Solution: refactor concat_fname() and remove calls to strlen() (John Marriott) Function `concat_fnames()` can make up to 5 calls to `STRLEN()` (either directly or indirectly via `STRCAT()`). In many cases the lengths of arguments `fname1` and/or `fname2` are either known or can simply be calculated. This Commit refactors this function to accept the lengths of arguments `fname1` and `fname2` as arguments. It also adds new argument `ret` to return the resulting string as a `string_T`. Additionally: - function `add_pack_dir_to_rtp()` in `scriptfile.c`: Use a `string_T` to store local variables `new_rtp` and `afterdir`. Replace calls to `STRCAT()` with calls to `STRCPY()`. Change type of variable `keep` to `size_t` for consistency with other lengths. - function `qf_get_fnum()` in `quickfix.c`: Use a `string_T` to store local variables `ptr` and `bufname` - function `qf_push_dir()` in `quickfix.c`: Use a `string_T` to store local variable `dirname`. Replace call to `vim_strsave()` with `vim_strnsave()`. - function `qf_guess_filepath()` in `quickfix.c`: Use a `string_T` to store local variable `fullname`. - function `make_percent_swname()` in `memline.c`: Rename some variables to better reflect their use. Use a `string_T` to store local variables `d` and `fixed_name`. Slightly refactor to remove need to create an extra string. - function `get_file_in_dir()` in `memline.c`: Use a `string_T` to store local variables `tail` and `retval`. Move some variables closer to where they are used. - function `cs_resolve_file()` in `if_cscope.c`: Use a `string_T` to store local variable `csdir`. Remove one call to `STRLEN()`. - function `add_pathsep()` in `filepath.c`: Refactor and remove 1 call to `STRLEN()` - function `set_init_xdg_rtp()` in `option.c`: Use a `string_T` to store local variable `vimrc_xdg`. closes: vim/vim#19854 https://github.com/vim/vim/commit/cb51add7ae400a47407fb7fb7b7a54e238d4fdf4 Co-authored-by: John Marriott Co-authored-by: Christian Brabandt --- src/nvim/main.c | 5 ++- src/nvim/memline.c | 79 ++++++++++++++++++--------------- src/nvim/os/env.c | 11 +++-- src/nvim/path.c | 33 ++++++++------ src/nvim/path.h | 1 + src/nvim/quickfix.c | 53 +++++++++++----------- src/nvim/runtime.c | 105 +++++++++++++++++++++++++------------------- src/nvim/undo.c | 18 ++++---- 8 files changed, 172 insertions(+), 133 deletions(-) diff --git a/src/nvim/main.c b/src/nvim/main.c index 5e64681cb5..62500066e9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1503,9 +1503,10 @@ scripterror: if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 && !os_isdir(alist_name(&GARGLIST[0]))) { - char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true); + const char *tail = path_tail(alist_name(&GARGLIST[0])); + String ret = concat_fnames(cstr_as_string(p), cstr_as_string(tail), true); xfree(p); - p = r; + p = ret.data; } #ifdef CASE_INSENSITIVE_FILENAME diff --git a/src/nvim/memline.c b/src/nvim/memline.c index a6bc0dd543..b89b75d913 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1327,11 +1327,11 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn } } else { // check directory dir_name if (fname == NULL) { - names[0] = concat_fnames(dir_name.data, "*.sw?", true); + names[0] = concat_fnames(dir_name, STATIC_CSTR_AS_STRING("*.sw?"), true).data; // For Unix names starting with a dot are special. MS-Windows // supports this too, on some file systems. - names[1] = concat_fnames(dir_name.data, ".*.sw?", true); - names[2] = concat_fnames(dir_name.data, ".sw?", true); + names[1] = concat_fnames(dir_name, STATIC_CSTR_AS_STRING(".*.sw?"), true).data; + names[2] = concat_fnames(dir_name, STATIC_CSTR_AS_STRING(".sw?"), true).data; num_names = 3; } else { p = dir_name.data + dir_name.size; @@ -1340,7 +1340,7 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn tail = make_percent_swname(dir_name.data, p, fname_res); } else { tail = path_tail(fname_res); - tail = concat_fnames(dir_name.data, tail, true); + tail = concat_fnames(dir_name, cstr_as_string(tail), true).data; } num_names = recov_file_names(names, tail, false); xfree(tail); @@ -1433,8 +1433,8 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn ui_flush(); } else if (ret_list != NULL) { for (int i = 0; i < num_files; i++) { - char *name = concat_fnames(dir_name.data, files[i], true); - tv_list_append_allocated_string(ret_list, name); + String name = concat_fnames(dir_name, cstr_as_string(files[i]), true); + tv_list_append_allocated_string(ret_list, name.data); } } else { file_count += num_files; @@ -1459,24 +1459,27 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn char *make_percent_swname(char *dir, char *dir_end, const char *name) FUNC_ATTR_NONNULL_ARG(1, 2) { - char *d = NULL; - char *f = fix_fname(name != NULL ? name : ""); - if (f == NULL) { + String fixed_fname; + fixed_fname.data = fix_fname(name != NULL ? name : ""); + if (fixed_fname.data == NULL) { return NULL; } - char *s = xstrdup(f); - for (d = s; *d != NUL; MB_PTR_ADV(d)) { - if (vim_ispathsep(*d)) { - *d = '%'; + char *p; + for (p = fixed_fname.data; *p != NUL; MB_PTR_ADV(p)) { + if (vim_ispathsep(*p)) { + *p = '%'; } } + fixed_fname.size = (size_t)(p - fixed_fname.data); - dir_end[-1] = NUL; // remove one trailing slash - d = concat_fnames(dir, s, true); - xfree(s); - xfree(f); - return d; + // remove one trailing slash + p = &dir_end[-1]; + *p = NUL; + String d = concat_fnames(cbuf_as_string(dir, (size_t)(p - dir)), fixed_fname, true); + xfree(fixed_fname.data); + + return d.data; } // PID of swapfile owner, or zero if not running. @@ -1684,7 +1687,8 @@ static int recov_file_names(char **names, char *path, bool prepend_dot) } // Form the normal swapfile name pattern by appending ".sw?". - names[num_names] = concat_fnames(path, ".sw?", false); + names[num_names] = concat_fnames(cstr_as_string(path), + STATIC_CSTR_AS_STRING(".sw?"), false).data; if (num_names >= 1) { // check if we have the same name twice char *p = names[num_names - 1]; int i = (int)strlen(names[num_names - 1]) - (int)strlen(names[num_names]); @@ -3327,28 +3331,31 @@ char *makeswapname(char *fname, char *ffname, buf_T *buf, char *dir_name) /// @param dname don't use "dirname", it is a global for Alpha char *get_file_in_dir(char *fname, char *dname) { - char *retval; - - char *tail = path_tail(fname); + String retval; + String tail = cstr_as_string(path_tail(fname)); if (dname[0] == '.' && dname[1] == NUL) { - retval = xstrdup(fname); - } else if (dname[0] == '.' && vim_ispathsep(dname[1])) { - if (tail == fname) { // no path before file name - retval = concat_fnames(dname + 2, tail, true); - } else { - char save_char = *tail; - *tail = NUL; - char *t = concat_fnames(fname, dname + 2, true); - *tail = save_char; - retval = concat_fnames(t, tail, true); - xfree(t); - } + retval = cbuf_to_string(fname, (size_t)(tail.data - fname) + tail.size); } else { - retval = concat_fnames(dname, tail, true); + size_t dname_len = strlen(dname); + if (dname[0] == '.' && vim_ispathsep(dname[1])) { + if (tail.data == fname) { // no path before file name + retval = concat_fnames(cbuf_as_string(dname + 2, dname_len - 2), tail, true); + } else { + const char save_char = *tail.data; + *tail.data = NUL; + String tmp = concat_fnames(cbuf_as_string(fname, (size_t)(tail.data - fname)), + cbuf_as_string(dname + 2, dname_len - 2), true); + *tail.data = save_char; + retval = concat_fnames(tmp, tail, true); + xfree(tmp.data); + } + } else { + retval = concat_fnames(cbuf_as_string(dname, dname_len), tail, true); + } } - return retval; + return retval.data; } /// Build the ATTENTION message: info about an existing swapfile. diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 8d62a00fbd..e2eecf3006 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -9,6 +9,7 @@ #include #include "auto/config.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" @@ -826,11 +827,13 @@ static char *vim_runtime_dir(const char *vimdir) if (vimdir == NULL || *vimdir == NUL) { return NULL; } - char *p = concat_fnames(vimdir, RUNTIME_DIRNAME, true); - if (os_isdir(p)) { - return p; + size_t vimdir_len = strlen(vimdir); + String p = concat_fnames(cbuf_as_string((char *)vimdir, vimdir_len), + STATIC_CSTR_AS_STRING(RUNTIME_DIRNAME), true); + if (os_isdir(p.data)) { + return p.data; } - xfree(p); + xfree(p.data); return NULL; } diff --git a/src/nvim/path.c b/src/nvim/path.c index ad12b39079..6ac594529c 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -443,14 +443,16 @@ int path_fnamencmp(const char *const fname1, const char *const fname2, size_t le /// /// @return fname1 static inline char *do_concat_fnames(char *fname1, const size_t len1, const char *fname2, - const size_t len2, const bool sep) + const size_t len2, const bool sep, size_t *len) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { if (sep && *fname1 && !after_pathsep(fname1, fname1 + len1)) { fname1[len1] = PATHSEP; memmove(fname1 + len1 + 1, fname2, len2 + 1); + *len = len1 + 1 + len2; } else { memmove(fname1 + len1, fname2, len2 + 1); + *len = len1 + len2; } return fname1; @@ -465,14 +467,14 @@ static inline char *do_concat_fnames(char *fname1, const size_t len1, const char /// @param sep is a flag to indicate a path separator should be added /// if necessary /// @return [allocated] Concatenation of fname1 and fname2. -char *concat_fnames(const char *fname1, const char *fname2, bool sep) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +String concat_fnames(String fname1, String fname2, bool sep) + FUNC_ATTR_NONNULL_ALL { - const size_t len1 = strlen(fname1); - const size_t len2 = strlen(fname2); - char *dest = xmalloc(len1 + len2 + 3); - memmove(dest, fname1, len1 + 1); - return do_concat_fnames(dest, len1, fname2, len2, sep); + String ret; + ret.data = xmalloc(fname1.size + (sep ? 1 : 0) + fname2.size + 1); + memmove(ret.data, fname1.data, fname1.size + 1); + do_concat_fnames(ret.data, fname1.size, fname2.data, fname2.size, sep, &ret.size); + return ret; } /// Concatenate file names fname1 and fname2 @@ -491,8 +493,9 @@ char *concat_fnames_realloc(char *fname1, const char *fname2, bool sep) { const size_t len1 = strlen(fname1); const size_t len2 = strlen(fname2); + size_t len; return do_concat_fnames(xrealloc(fname1, len1 + len2 + 3), len1, - fname2, len2, sep); + fname2, len2, sep, &len); } /// Adds a path separator to a filename, unless it already ends in one. @@ -502,13 +505,17 @@ char *concat_fnames_realloc(char *fname1, const char *fname2, bool sep) bool add_pathsep(char *p) FUNC_ATTR_NONNULL_ALL { - const size_t len = strlen(p); - if (*p != NUL && !after_pathsep(p, p + len)) { + if (*p == NUL) { + return true; + } + + const size_t plen = strlen(p); + if (!after_pathsep(p, p + plen)) { const size_t pathsep_len = sizeof(PATHSEPSTR); - if (len > MAXPATHL - pathsep_len) { + if (plen > MAXPATHL - pathsep_len) { return false; } - memcpy(p + len, PATHSEPSTR, pathsep_len); + memcpy(p + plen, PATHSEPSTR, pathsep_len); } return true; } diff --git a/src/nvim/path.h b/src/nvim/path.h index 3780d0bfdc..ff898d3550 100644 --- a/src/nvim/path.h +++ b/src/nvim/path.h @@ -2,6 +2,7 @@ #include // IWYU pragma: keep +#include "nvim/api/private/defs.h" // IWYU pragma: keep #include "nvim/garray_defs.h" // IWYU pragma: keep #include "nvim/types_defs.h" // IWYU pragma: keep diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index fbbe439455..3fea62e68a 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2307,8 +2307,8 @@ void copy_loclist_stack(win_T *from, win_T *to) /// Also sets the b_has_qf_entry flag. static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) { - char *ptr = NULL; - char *bufname; + String ptr = STRING_INIT; + String bufname; buf_T *buf; if (fname == NULL || *fname == NUL) { // no file name return 0; @@ -2320,43 +2320,43 @@ static int qf_get_fnum(qf_list_T *qfl, char *directory, char *fname) } slash_adjust(fname); #endif + String fname_str = cstr_as_string(fname); if (directory != NULL && !vim_isAbsName(fname)) { - ptr = concat_fnames(directory, fname, true); + ptr = concat_fnames(cstr_as_string(directory), fname_str, true); // Here we check if the file really exists. // This should normally be true, but if make works without // "leaving directory"-messages we might have missed a // directory change. - if (!os_path_exists(ptr)) { - xfree(ptr); + if (!os_path_exists(ptr.data)) { + xfree(ptr.data); directory = qf_guess_filepath(qfl, fname); if (directory) { - ptr = concat_fnames(directory, fname, true); + ptr = concat_fnames(cstr_as_string(directory), fname_str, true); } else { - ptr = xstrdup(fname); + ptr = copy_string(fname_str, NULL); } } // Use concatenated directory name and file name. bufname = ptr; } else { - bufname = fname; + bufname = fname_str; } - if (qf_last_bufname != NULL - && strcmp(bufname, qf_last_bufname) == 0 + if (qf_last_bufname != NULL && strcmp(bufname.data, qf_last_bufname) == 0 && bufref_valid(&qf_last_bufref)) { buf = qf_last_bufref.br_buf; - xfree(ptr); + xfree(ptr.data); } else { xfree(qf_last_bufname); - buf = buflist_new(bufname, NULL, 0, BLN_NOOPT); - qf_last_bufname = (bufname == ptr) ? bufname : xstrdup(bufname); + buf = buflist_new(bufname.data, NULL, 0, BLN_NOOPT); + qf_last_bufname = (bufname.data == ptr.data) + ? bufname.data : xmemdupz(bufname.data, bufname.size); set_bufref(&qf_last_bufref, buf); } if (buf == NULL) { return 0; } - buf->b_has_qf_entry = - IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; + buf->b_has_qf_entry = IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; return buf->b_fnum; } @@ -2382,16 +2382,18 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi // Okay we don't have an absolute path. // dirbuf must be a subdir of one of the directories on the stack. // Let's search... + size_t dirbuf_len = strlen(dirbuf); ds_new = (*stackptr)->next; (*stackptr)->dirname = NULL; while (ds_new) { - char *dirname = concat_fnames(ds_new->dirname, dirbuf, true); - if (os_isdir(dirname)) { + String dirname = concat_fnames(cstr_as_string(ds_new->dirname), + cbuf_as_string(dirbuf, dirbuf_len), true); + if (os_isdir(dirname.data)) { xfree((*stackptr)->dirname); - (*stackptr)->dirname = dirname; + (*stackptr)->dirname = dirname.data; break; } - xfree(dirname); + xfree(dirname.data); ds_new = ds_new->next; } @@ -2406,7 +2408,7 @@ static char *qf_push_dir(char *dirbuf, struct dir_stack_T **stackptr, bool is_fi // Nothing found -> it must be on top level if (ds_new == NULL) { xfree((*stackptr)->dirname); - (*stackptr)->dirname = xstrdup(dirbuf); + (*stackptr)->dirname = xmemdupz(dirbuf, dirbuf_len); } } @@ -2479,19 +2481,20 @@ static char *qf_guess_filepath(qf_list_T *qfl, char *filename) } struct dir_stack_T *ds_ptr = qfl->qf_dir_stack->next; - char *fullname = NULL; + String fullname = STRING_INIT; + String filename_str = cstr_as_string(filename); while (ds_ptr) { - xfree(fullname); - fullname = concat_fnames(ds_ptr->dirname, filename, true); + xfree(fullname.data); + fullname = concat_fnames(cstr_as_string(ds_ptr->dirname), filename_str, true); - if (os_path_exists(fullname)) { + if (os_path_exists(fullname.data)) { break; } ds_ptr = ds_ptr->next; } - xfree(fullname); + xfree(fullname.data); // clean up all dirs we already left while (qfl->qf_dir_stack->next != ds_ptr) { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 47e1feface..8f577b971d 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -1029,7 +1029,7 @@ static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool /// @param is_pack whether the added dir is a "pack/*/start/*/" style package static int add_pack_dir_to_rtp(char *fname, bool is_pack) { - char *afterdir = NULL; + String afterdir = STRING_INIT; int retval = FAIL; char *p1 = get_past_head(fname); @@ -1063,17 +1063,24 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences // Also stop at the first "after" directory size_t fname_len = strlen(ffname); - char buf[MAXPATHL]; + char buf_data[MAXPATHL]; + String buf; + buf.data = buf_data; + const char *insp = NULL; const char *after_insp = NULL; + size_t p_rtp_len = 0; const char *entry = p_rtp; while (*entry != NUL) { const char *cur_entry = entry; - copy_option_part((char **)&entry, buf, MAXPATHL, ","); + buf.size = copy_option_part((char **)&entry, buf.data, MAXPATHL, ","); - char *p = strstr(buf, "after"); + // keep track of p_rtp length as we go to make the strlen() below have less work to do + p_rtp_len += (*(p_rtp + buf.size) == ',') ? buf.size + 1 : buf.size; + + char *p = strstr(buf.data, "after"); bool is_after = p != NULL - && p > buf + && p > buf.data && vim_ispathsep(p[-1]) && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','); @@ -1088,8 +1095,8 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) } if (insp == NULL) { - add_pathsep(buf); - char *const rtp_ffname = fix_fname(buf); + add_pathsep(buf.data); + char *const rtp_ffname = fix_fname(buf.data); if (rtp_ffname == NULL) { goto theend; } @@ -1101,24 +1108,25 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) } } + // finish measuring the length of p_rtp + p_rtp_len += strlen(p_rtp + p_rtp_len); if (insp == NULL) { // Both "fname" and "after" not found, append at the end. - insp = p_rtp + strlen(p_rtp); + insp = p_rtp + p_rtp_len; } // check if rtp/pack/name/start/name/after exists - afterdir = concat_fnames(fname, "after", true); - size_t afterlen = 0; - if (is_pack ? pack_has_entries(afterdir) : os_isdir(afterdir)) { - afterlen = strlen(afterdir) + 1; // add one for comma + fname_len = strlen(fname); + afterdir = concat_fnames(cbuf_as_string(fname, fname_len), STATIC_CSTR_AS_STRING("after"), true); + if (is_pack ? !pack_has_entries(afterdir.data) : !os_isdir(afterdir.data)) { + afterdir.size = 0; } - const size_t oldlen = strlen(p_rtp); - const size_t addlen = strlen(fname) + 1; // add one for comma - const size_t new_rtp_capacity = oldlen + addlen + afterlen + 1; - // add one for NUL ------------------------------------------^ - char *const new_rtp = try_malloc(new_rtp_capacity); - if (new_rtp == NULL) { + const size_t new_rtp_capacity = p_rtp_len + fname_len + afterdir.size + 3; + // add two for commas and one more for NUL -----------------------------^ + String new_rtp; + new_rtp.data = try_malloc(new_rtp_capacity); + if (new_rtp.data == NULL) { goto theend; } @@ -1126,49 +1134,54 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) // Create new_rtp, first: {keep},{fname} size_t keep = (size_t)(insp - p_rtp); size_t first_pos = keep; - memmove(new_rtp, p_rtp, keep); - size_t new_rtp_len = keep; + memmove(new_rtp.data, p_rtp, keep); + new_rtp.size = keep; if (*insp == NUL) { - new_rtp[new_rtp_len++] = ','; // add comma before + new_rtp.data[new_rtp.size++] = ','; // add comma before first_pos++; } - memmove(new_rtp + new_rtp_len, fname, addlen - 1); - new_rtp_len += addlen - 1; + memmove(new_rtp.data + new_rtp.size, fname, fname_len); + new_rtp.size += fname_len; if (*insp != NUL) { - new_rtp[new_rtp_len++] = ','; // add comma after + new_rtp.data[new_rtp.size++] = ','; // add comma after } size_t after_pos = 0; - if (afterlen > 0 && after_insp != NULL) { + if (afterdir.size > 0 && after_insp != NULL) { size_t keep_after = (size_t)(after_insp - p_rtp); + size_t append_len = keep_after - keep; // Add to new_rtp: {keep},{fname}{keep_after},{afterdir} - memmove(new_rtp + new_rtp_len, p_rtp + keep, keep_after - keep); - new_rtp_len += keep_after - keep; - memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1); - new_rtp_len += afterlen - 1; - new_rtp[new_rtp_len++] = ','; + memmove(new_rtp.data + new_rtp.size, p_rtp + keep, append_len); + new_rtp.size += append_len; + memmove(new_rtp.data + new_rtp.size, afterdir.data, afterdir.size); + new_rtp.size += afterdir.size; + new_rtp.data[new_rtp.size++] = ','; keep = keep_after; after_pos = keep_after; } if (p_rtp[keep] != NUL) { + size_t append_len = p_rtp_len - keep; // Append rest: {keep},{fname}{keep_after},{afterdir}{rest} - memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1); + memmove(new_rtp.data + new_rtp.size, p_rtp + keep, append_len + 1); // add one for NUL + new_rtp.size += append_len; } else { - new_rtp[new_rtp_len] = NUL; + new_rtp.data[new_rtp.size] = NUL; } - if (afterlen > 0 && after_insp == NULL) { + if (afterdir.size > 0 && after_insp == NULL) { // Append afterdir when "after" was not found: // {keep},{fname}{rest},{afterdir} - after_pos = xstrlcat(new_rtp, ",", new_rtp_capacity); - xstrlcat(new_rtp, afterdir, new_rtp_capacity); + new_rtp.data[new_rtp.size++] = ','; + after_pos = new_rtp.size; + memmove(new_rtp.data + new_rtp.size, afterdir.data, afterdir.size + 1); // add one for NUL + new_rtp.size += afterdir.size; } bool was_valid = runtime_search_path_valid; - set_option_value_give_err(kOptRuntimepath, CSTR_AS_OPTVAL(new_rtp), 0); + set_option_value_give_err(kOptRuntimepath, STRING_OPTVAL(new_rtp), 0); assert(!runtime_search_path_valid); // If this is the result of "packadd opt_pack", rebuilding runtime_search_pat @@ -1181,16 +1194,17 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) kv_pushp(runtime_search_path); ssize_t i = (ssize_t)(kv_size(runtime_search_path)) - 1; - if (afterlen > 0) { + if (afterdir.size > 0) { kv_pushp(runtime_search_path); i += 1; for (; i >= 1; i--) { if (i > 1 && kv_A(runtime_search_path, i - 2).pos_in_rtp >= after_pos) { kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 2); - kv_A(runtime_search_path, i).pos_in_rtp += addlen + afterlen; + kv_A(runtime_search_path, i).pos_in_rtp += fname_len + afterdir.size + 2; } else { - kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(afterdir), true, true, kNone, - after_pos + addlen }; + kv_A(runtime_search_path, i) = (SearchPathItem){ + xmemdupz(afterdir.data, afterdir.size), true, true, kNone, after_pos + fname_len + 1, + }; i--; break; } @@ -1200,20 +1214,21 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack) for (; i >= 0; i--) { if (i > 0 && kv_A(runtime_search_path, i - 1).pos_in_rtp >= first_pos) { kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 1); - kv_A(runtime_search_path, i).pos_in_rtp += addlen; + kv_A(runtime_search_path, i).pos_in_rtp += fname_len + 1; } else { - kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(fname), false, true, kNone, - first_pos }; + kv_A(runtime_search_path, i) = (SearchPathItem){ + xmemdupz(fname, fname_len), false, true, kNone, first_pos + }; break; } } } - xfree(new_rtp); + xfree(new_rtp.data); retval = OK; theend: xfree(ffname); - xfree(afterdir); + xfree(afterdir.data); return retval; } diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 4a38a36dac..4a4e0daba7 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -688,9 +688,10 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) #endif char dir_name[MAXPATHL + 1]; - char *munged_name = NULL; + String munged_name = STRING_INIT; char *undo_file_name = NULL; + const size_t ffname_len = strlen(ffname); // Loop over 'undodir'. When reading find the first file that exists. // When not reading use the first directory that exists or ".". char *dirp = p_udir; @@ -699,11 +700,10 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) if (dir_len == 1 && dir_name[0] == '.') { // Use same directory as the ffname, // "dir/name" -> "dir/.name.un~" - const size_t ffname_len = strlen(ffname); undo_file_name = xmalloc(ffname_len + 6); memmove(undo_file_name, ffname, ffname_len + 1); char *const tail = path_tail(undo_file_name); - const size_t tail_len = strlen(tail); + const size_t tail_len = ffname_len - (size_t)(tail - undo_file_name); memmove(tail + 1, tail, tail_len + 1); *tail = '.'; memmove(tail + tail_len + 1, ".un~", sizeof(".un~")); @@ -714,6 +714,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) char *p = &dir_name[dir_len - 1]; while (vim_ispathsep(*p)) { *p-- = NUL; + dir_len--; } bool has_directory = os_isdir(dir_name); @@ -730,15 +731,16 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) } } if (has_directory) { - if (munged_name == NULL) { - munged_name = xstrdup(ffname); - for (char *c = munged_name; *c != NUL; MB_PTR_ADV(c)) { + if (munged_name.data == NULL) { + munged_name = cbuf_to_string(ffname, ffname_len); + for (char *c = munged_name.data; *c != NUL; MB_PTR_ADV(c)) { if (vim_ispathsep(*c)) { *c = '%'; } } } - undo_file_name = concat_fnames(dir_name, munged_name, true); + undo_file_name = concat_fnames(cbuf_as_string(dir_name, dir_len), + munged_name, true).data; } } @@ -750,7 +752,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) XFREE_CLEAR(undo_file_name); } - xfree(munged_name); + xfree(munged_name.data); return undo_file_name; }