patch 9.1.2004: MS-Windows: executable() cannot find file in directory with single char
Commit:
https://github.com/vim/vim/commit/bd686d85dc2b1488ab10c723125d654e0e2d7ef4
Author: Muraoka Taro <
koron....@gmail.com>
Date: Sun Dec 21 19:19:39 2025 +0000
patch 9.1.2004: MS-Windows: executable() cannot find file in directory with single char
Problem: MS-Windows: If a directory with a single character name is
included in the PATH environment variable without a trailing
path separator, executable() will not be able to find the
executable file under it.
Solution: The second argument of the after_pathsep() function is now
passed the next pointer where a path separator may exist
(Muraoka Taro).
As a specific example, the default installation path for PowerShell v7
is "C:\Program Files\PowerShell ", but if you set this as is in the
PATH environment variable, Vim will not be able to find the pwsh.exe
command. In this case, Vim will try to search for "C:\Program
Files\PowerShell pwsh.exe".
Cause: The after_pathsep() function determines whether the location
passed as its second argument immediately follows a path separator.
However, in the code where the problem occurred, the second argument was
passed a location that might contain a path separator. As a result, it
was mistakenly determined that a path separator was present in cases
where the final directory name was a single character and not followed
by a path separator, and the path to search was incorrect.
closes: #18979
Signed-off-by: Muraoka Taro <
koron....@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/os_win32.c b/src/os_win32.c
index 21b7023fa..ede7a15b2 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -2920,7 +2920,7 @@ executable_exists(
(char *)buf,
sizeof(buf),
"%.*s%s%s", (int)(e - p), p,
- !after_pathsep(p, e - 1) ? PATHSEPSTR : "",
+ !after_pathsep(p, e) ? PATHSEPSTR : "",
name);
}
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 9d66985d6..ec721d057 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -2140,6 +2140,41 @@ func Test_executable_longname()
call delete(fname)
endfunc
+func Test_executable_single_character_dir()
+ call mkdir('Xpath', 'R')
+ call mkdir('Xpath/a')
+ call mkdir('Xpath/b')
+ call mkdir('Xpath/c')
+ if has('win32')
+ call writefile([], 'Xpath/a/Xcmd1.bat')
+ call writefile([], 'Xpath/b/Xcmd2.bat')
+ call writefile([], 'Xpath/c/Xcmd3.bat')
+ let sep = ';'
+ else
+ call writefile([], 'Xpath/a/Xcmd1')
+ call writefile([], 'Xpath/b/Xcmd2')
+ call writefile([], 'Xpath/c/Xcmd3')
+ call setfperm('Xpath/a/Xcmd1', 'rwxr-xr-x')
+ call setfperm('Xpath/b/Xcmd2', 'rwxr-xr-x')
+ call setfperm('Xpath/c/Xcmd3', 'rwxr-xr-x')
+ let sep = ':'
+ endif
+
+ let save_path = $PATH
+ " a: single character name without path seperator
+ " b: single character name with path seperator
+ " c: single character name without path seperator at last of PATH
+ let $PATH = [
+ \ fnamemodify('./Xpath/a', ':p:h'),
+ \ fnamemodify('./Xpath/b', ':p'),
+ \ fnamemodify('./Xpath/c', ':p:h')
+ \ ]->join(sep)
+ call assert_true(executable('Xcmd1'))
+ call assert_true(executable('Xcmd2'))
+ call assert_true(executable('Xcmd3'))
+ let $PATH = save_path
+endfunc
+
func Test_hostname()
let hostname_vim = hostname()
if has('unix')
diff --git a/src/version.c b/src/version.c
index fbadafea2..a0cbb675e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2004,
/**/
2003,
/**/