vim-patch:9.1.1204: MS-Windows: crash when passing long string to expand() (#32902)

Problem:  MS-Windows: crash when passing long string to expand() with
          'wildignorecase'.
Solution: Use the same buflen as unix_expandpath() in dos_expandpath().
          Remove an unnecessary STRLEN() while at it (zeertzjq).

closes: vim/vim#16896

00a749bd90
(cherry picked from commit ec8fc28743)
This commit is contained in:
zeertzjq
2025-03-15 17:34:56 +08:00
committed by github-actions[bot]
parent aab7129abe
commit 0c995c0efb
2 changed files with 21 additions and 12 deletions

View File

@ -619,7 +619,6 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int start_len = gap->ga_len; int start_len = gap->ga_len;
size_t len;
bool starstar = false; bool starstar = false;
static int stardepth = 0; // depth for "**" expansion static int stardepth = 0; // depth for "**" expansion
@ -631,8 +630,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
} }
} }
// Make room for file name. When doing encoding conversion the actual // Make room for file name (a bit too much to stay on the safe side).
// length may be quite a bit longer, thus use the maximum possible length.
const size_t buflen = strlen(path) + MAXPATHL; const size_t buflen = strlen(path) + MAXPATHL;
char *buf = xmalloc(buflen); char *buf = xmalloc(buflen);
@ -663,10 +661,10 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
) { ) {
e = p; e = p;
} }
len = (size_t)(utfc_ptr2len(path_end)); int charlen = utfc_ptr2len(path_end);
memcpy(p, path_end, len); memcpy(p, path_end, (size_t)charlen);
p += len; p += charlen;
path_end += len; path_end += charlen;
} }
e = p; e = p;
*e = NUL; *e = NUL;
@ -720,13 +718,14 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
return 0; return 0;
} }
size_t len = (size_t)(s - buf);
// If "**" is by itself, this is the first time we encounter it and more // If "**" is by itself, this is the first time we encounter it and more
// is following then find matches without any directory. // is following then find matches without any directory.
if (!didstar && stardepth < 100 && starstar && e - s == 2 if (!didstar && stardepth < 100 && starstar && e - s == 2
&& *path_end == '/') { && *path_end == '/') {
STRCPY(s, path_end + 1); vim_snprintf(s, buflen - len, "%s", path_end + 1);
stardepth++; stardepth++;
do_path_expand(gap, buf, (size_t)(s - buf), flags, true); do_path_expand(gap, buf, len, flags, true);
stardepth--; stardepth--;
} }
*s = NUL; *s = NUL;
@ -738,6 +737,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
const char *name; const char *name;
scandir_next_with_dots(NULL); // initialize scandir_next_with_dots(NULL); // initialize
while (!got_int && (name = scandir_next_with_dots(&dir)) != NULL) { while (!got_int && (name = scandir_next_with_dots(&dir)) != NULL) {
len = (size_t)(s - buf);
if ((name[0] != '.' if ((name[0] != '.'
|| starts_with_dot || starts_with_dot
|| ((flags & EW_DODOT) || ((flags & EW_DODOT)
@ -745,9 +745,11 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in
&& (name[1] != '.' || name[2] != NUL))) && (name[1] != '.' || name[2] != NUL)))
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0)) && ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD) || ((flags & EW_NOTWILD)
&& path_fnamencmp(path + (s - buf), name, (size_t)(e - s)) == 0))) { && path_fnamencmp(path + len, name, (size_t)(e - s)) == 0))) {
xstrlcpy(s, name, buflen - (size_t)(s - buf)); len += (size_t)vim_snprintf(s, buflen - len, "%s", name);
len = strlen(buf); if (len + 1 >= buflen) {
continue;
}
if (starstar && stardepth < 100) { if (starstar && stardepth < 100) {
// For "**" in the pattern first go deeper in the tree to // For "**" in the pattern first go deeper in the tree to

View File

@ -143,4 +143,11 @@ func Test_expand_wildignore()
set wildignore& set wildignore&
endfunc endfunc
" Passing a long string to expand with 'wildignorecase' should not crash Vim.
func Test_expand_long_str()
set wildignorecase
call expand('a'->repeat(99999))
set wildignorecase&
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab