vim-patch:9.1.1122: too many strlen() calls in findfile.c (#32516)

Problem:  too many strlen() calls in findfile.c
Solution: refactor findfile.c and remove calls to strlen()
          (John Marriott)

closes: vim/vim#16595

d6e3c9048d

Co-authored-by: John Marriott <basilisk@internode.on.net>
This commit is contained in:
zeertzjq
2025-02-19 17:14:38 +08:00
committed by GitHub
parent 9005134cdc
commit a3eb49f638
3 changed files with 367 additions and 257 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -816,13 +816,13 @@ static int find_previous_pathsep(char *path, char **psep)
static bool is_unique(char *maybe_unique, garray_T *gap, int i) static bool is_unique(char *maybe_unique, garray_T *gap, int i)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
size_t candidate_len = strlen(maybe_unique);
char **other_paths = gap->ga_data; char **other_paths = gap->ga_data;
for (int j = 0; j < gap->ga_len; j++) { for (int j = 0; j < gap->ga_len; j++) {
if (j == i) { if (j == i) {
continue; // don't compare it with itself continue; // don't compare it with itself
} }
size_t candidate_len = strlen(maybe_unique);
size_t other_path_len = strlen(other_paths[j]); size_t other_path_len = strlen(other_paths[j]);
if (other_path_len < candidate_len) { if (other_path_len < candidate_len) {
continue; // it's different when it's shorter continue; // it's different when it's shorter
@@ -849,9 +849,10 @@ static void expand_path_option(char *curdir, char *path_option, garray_T *gap)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
char *buf = xmalloc(MAXPATHL); char *buf = xmalloc(MAXPATHL);
size_t curdirlen = 0;
while (*path_option != NUL) { while (*path_option != NUL) {
copy_option_part(&path_option, buf, MAXPATHL, " ,"); size_t buflen = copy_option_part(&path_option, buf, MAXPATHL, " ,");
if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1]))) { if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1]))) {
// Relative to current buffer: // Relative to current buffer:
@@ -861,34 +862,40 @@ static void expand_path_option(char *curdir, char *path_option, garray_T *gap)
continue; continue;
} }
char *p = path_tail(curbuf->b_ffname); char *p = path_tail(curbuf->b_ffname);
size_t len = (size_t)(p - curbuf->b_ffname); size_t plen = (size_t)(p - curbuf->b_ffname);
if (len + strlen(buf) >= MAXPATHL) { if (plen + strlen(buf) >= MAXPATHL) {
continue; continue;
} }
if (buf[1] == NUL) { if (buf[1] == NUL) {
buf[len] = NUL; buf[plen] = NUL;
} else { } else {
STRMOVE(buf + len, buf + 2); memmove(buf + plen, buf + 2, (buflen - 2) + 1); // +1 for NUL
} }
memmove(buf, curbuf->b_ffname, len); memmove(buf, curbuf->b_ffname, plen);
simplify_filename(buf); buflen = simplify_filename(buf);
} else if (buf[0] == NUL) { } else if (buf[0] == NUL) {
STRCPY(buf, curdir); // relative to current directory STRCPY(buf, curdir); // relative to current directory
if (curdirlen == 0) {
curdirlen = strlen(curdir);
}
buflen = curdirlen;
} else if (path_with_url(buf)) { } else if (path_with_url(buf)) {
continue; // URL can't be used here continue; // URL can't be used here
} else if (!path_is_absolute(buf)) { } else if (!path_is_absolute(buf)) {
// Expand relative path to their full path equivalent // Expand relative path to their full path equivalent
size_t len = strlen(curdir); if (curdirlen == 0) {
if (len + strlen(buf) + 3 > MAXPATHL) { curdirlen = strlen(curdir);
}
if (curdirlen + buflen + 3 > MAXPATHL) {
continue; continue;
} }
STRMOVE(buf + len + 1, buf); memmove(buf + curdirlen + 1, buf, buflen + 1); // +1 for NUL
STRCPY(buf, curdir); STRCPY(buf, curdir);
buf[len] = PATHSEP; buf[curdirlen] = PATHSEP;
simplify_filename(buf); buflen = simplify_filename(buf);
} }
GA_APPEND(char *, gap, xstrdup(buf)); GA_APPEND(char *, gap, xmemdupz(buf, buflen));
} }
xfree(buf); xfree(buf);
@@ -959,7 +966,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
char *file_pattern = xmalloc(len + 2); char *file_pattern = xmalloc(len + 2);
file_pattern[0] = '*'; file_pattern[0] = '*';
file_pattern[1] = NUL; file_pattern[1] = NUL;
strcat(file_pattern, pattern); STRCPY(file_pattern + 1, pattern);
char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, false); char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, false);
xfree(file_pattern); xfree(file_pattern);
if (pat == NULL) { if (pat == NULL) {
@@ -987,7 +994,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
bool is_in_curdir = path_fnamencmp(curdir, path, (size_t)(dir_end - path)) == 0 bool is_in_curdir = path_fnamencmp(curdir, path, (size_t)(dir_end - path)) == 0
&& curdir[dir_end - path] == NUL; && curdir[dir_end - path] == NUL;
if (is_in_curdir) { if (is_in_curdir) {
in_curdir[i] = xstrdup(path); in_curdir[i] = xmemdupz(path, len);
} }
// Shorten the filename while maintaining its uniqueness // Shorten the filename while maintaining its uniqueness
@@ -1012,7 +1019,8 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
&& is_unique(pathsep_p + 1, gap, i) && is_unique(pathsep_p + 1, gap, i)
&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) { && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) {
sort_again = true; sort_again = true;
memmove(path, pathsep_p + 1, strlen(pathsep_p)); memmove(path, pathsep_p + 1,
(size_t)((path + len) - (pathsep_p + 1)) + 1); // +1 for NUL
break; break;
} }
} }
@@ -1031,9 +1039,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
// c:\file.txt c:\ .\file.txt // c:\file.txt c:\ .\file.txt
short_name = path_shorten_fname(path, curdir); short_name = path_shorten_fname(path, curdir);
if (short_name != NULL && short_name > path + 1) { if (short_name != NULL && short_name > path + 1) {
STRCPY(path, "."); vim_snprintf(path, MAXPATHL, ".%s%s", PATHSEPSTR, short_name);
add_pathsep(path);
STRMOVE(path + strlen(path), short_name);
} }
} }
os_breakcheck(); os_breakcheck();
@@ -1041,7 +1047,6 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
// Shorten filenames in /in/current/directory/{filename} // Shorten filenames in /in/current/directory/{filename}
for (int i = 0; i < gap->ga_len && !got_int; i++) { for (int i = 0; i < gap->ga_len && !got_int; i++) {
char *rel_path;
char *path = in_curdir[i]; char *path = in_curdir[i];
if (path == NULL) { if (path == NULL) {
@@ -1059,10 +1064,10 @@ static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option)
continue; continue;
} }
rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2); size_t rel_pathsize = 1 + STRLEN_LITERAL(PATHSEPSTR) + strlen(short_name) + 1;
STRCPY(rel_path, "."); char *rel_path = xmalloc(rel_pathsize);
add_pathsep(rel_path);
strcat(rel_path, short_name); vim_snprintf(rel_path, rel_pathsize, ".%s%s", PATHSEPSTR, short_name);
xfree(fnames[i]); xfree(fnames[i]);
fnames[i] = rel_path; fnames[i] = rel_path;
@@ -1518,7 +1523,7 @@ void addfile(garray_T *gap, char *f, int flags)
// its simplest form by stripping out unneeded components, if any. The // its simplest form by stripping out unneeded components, if any. The
// resulting file name is simplified in place and will either be the same // resulting file name is simplified in place and will either be the same
// length as that supplied, or shorter. // length as that supplied, or shorter.
void simplify_filename(char *filename) size_t simplify_filename(char *filename)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int components = 0; int components = 0;
@@ -1539,10 +1544,12 @@ void simplify_filename(char *filename)
} while (vim_ispathsep(*p)); } while (vim_ispathsep(*p));
} }
char *start = p; // remember start after "c:/" or "/" or "///" char *start = p; // remember start after "c:/" or "/" or "///"
char *p_end = p + strlen(p); // point to NUL at end of string "p"
#ifdef UNIX #ifdef UNIX
// Posix says that "//path" is unchanged but "///path" is "/path". // Posix says that "//path" is unchanged but "///path" is "/path".
if (start > filename + 2) { if (start > filename + 2) {
STRMOVE(filename + 1, p); memmove(filename + 1, p, (size_t)(p_end - p) + 1); // +1 for NUL
p_end -= (size_t)(p - (filename + 1));
start = p = filename + 1; start = p = filename + 1;
} }
#endif #endif
@@ -1551,7 +1558,8 @@ void simplify_filename(char *filename)
// At this point "p" is pointing to the char following a single "/" // At this point "p" is pointing to the char following a single "/"
// or "p" is at the "start" of the (absolute or relative) path name. // or "p" is at the "start" of the (absolute or relative) path name.
if (vim_ispathsep(*p)) { if (vim_ispathsep(*p)) {
STRMOVE(p, p + 1); // remove duplicate "/" memmove(p, p + 1, (size_t)(p_end - (p + 1)) + 1); // remove duplicate "/"
p_end--;
} else if (p[0] == '.' } else if (p[0] == '.'
&& (vim_ispathsep(p[1]) || p[1] == NUL)) { && (vim_ispathsep(p[1]) || p[1] == NUL)) {
if (p == start && relative) { if (p == start && relative) {
@@ -1569,7 +1577,8 @@ void simplify_filename(char *filename)
} else if (p > start) { } else if (p > start) {
p--; // strip preceding path separator p--; // strip preceding path separator
} }
STRMOVE(p, tail); memmove(p, tail, (size_t)(p_end - tail) + 1);
p_end -= (size_t)(tail - p);
} }
} else if (p[0] == '.' && p[1] == '.' } else if (p[0] == '.' && p[1] == '.'
&& (vim_ispathsep(p[2]) || p[2] == NUL)) { && (vim_ispathsep(p[2]) || p[2] == NUL)) {
@@ -1667,16 +1676,19 @@ void simplify_filename(char *filename)
if (p > start && tail[-1] == '.') { if (p > start && tail[-1] == '.') {
p--; p--;
} }
STRMOVE(p, tail); // strip previous component memmove(p, tail, (size_t)(p_end - tail) + 1); // strip previous component
p_end -= (size_t)(tail - p);
} }
components--; components--;
} }
} else if (p == start && !relative) { // leading "/.." or "/../" } else if (p == start && !relative) { // leading "/.." or "/../"
STRMOVE(p, tail); // strip ".." or "../" memmove(p, tail, (size_t)(p_end - tail) + 1); // strip ".." or "../"
p_end -= (size_t)(tail - p);
} else { } else {
if (p == start + 2 && p[-2] == '.') { // leading "./../" if (p == start + 2 && p[-2] == '.') { // leading "./../"
STRMOVE(p - 2, p); // strip leading "./" memmove(p - 2, p, (size_t)(p_end - p) + 1); // strip leading "./"
p_end -= 2;
tail -= 2; tail -= 2;
} }
p = tail; // skip to char after ".." or "../" p = tail; // skip to char after ".." or "../"
@@ -1686,6 +1698,8 @@ void simplify_filename(char *filename)
p = (char *)path_next_component(p); p = (char *)path_next_component(p);
} }
} while (*p != NUL); } while (*p != NUL);
return (size_t)(p_end - filename);
} }
/// Checks for a Windows drive letter ("C:/") at the start of the path. /// Checks for a Windows drive letter ("C:/") at the start of the path.

View File

@@ -2556,7 +2556,7 @@ int get_tagfname(tagname_T *tnp, int first, char *buf)
STRMOVE(filename + 1, filename); STRMOVE(filename + 1, filename);
*filename++ = NUL; *filename++ = NUL;
tnp->tn_search_ctx = vim_findfile_init(buf, filename, tnp->tn_search_ctx = vim_findfile_init(buf, filename, strlen(filename),
r_ptr, 100, r_ptr, 100,
false, // don't free visited list false, // don't free visited list
FINDFILE_FILE, // we search for a file FINDFILE_FILE, // we search for a file