neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 19a3b6778979e0b328f9a791a9f92296fd406690
parent 484f4554021f3ecc169c1d57bf911deefdd35eda
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Thu, 29 Jan 2026 22:02:24 +0800

fix(process): avoid unexpected behavior when PTY chdir failed (#37614)

Problem:  Unexpected behavior after PTY child process fails to chdir(),
          as it then thinks it's the parent process.
Solution: Exit the child process instead of returning.
Diffstat:
Msrc/nvim/os/pty_proc_unix.c | 4++--
Mtest/functional/core/job_spec.lua | 34+++++++++++++++++++++++++++++-----
2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/src/nvim/os/pty_proc_unix.c b/src/nvim/os/pty_proc_unix.c @@ -263,7 +263,7 @@ void pty_proc_teardown(Loop *loop) } static void init_child(PtyProc *ptyproc) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NORETURN { #if defined(HAVE__NSGETENVIRON) # define environ (*_NSGetEnviron()) @@ -285,7 +285,7 @@ static void init_child(PtyProc *ptyproc) // Don't use os_chdir() as that may buffer UI events unnecessarily. if (proc->cwd && (err = uv_chdir(proc->cwd)) != 0) { ELOG("chdir(%s) failed: %s", proc->cwd, uv_strerror(err)); - return; + _exit(122); } const char *prog = proc_get_exepath(proc); diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua @@ -297,18 +297,42 @@ describe('jobs', function() end) it('error on non-executable `cwd`', function() - if is_os('win') then - return -- Not applicable for Windows. - end + skip(is_os('win'), 'N/A for Windows') local dir = 'Xtest_not_executable_dir' mkdir(dir) + finally(function() + rmdir(dir) + end) fn.setfperm(dir, 'rw-------') + matches( '^Vim%(call%):E903: Process failed to start: permission denied: .*', - pcall_err(command, "call jobstart(['pwd'], {'cwd': '" .. dir .. "'})") + pcall_err(command, ("call jobstart(['pwd'], {'cwd': '%s'})"):format(dir)) ) - rmdir(dir) + end) + + it('error log and exit status 122 on non-executable `cwd`', function() + skip(is_os('win'), 'N/A for Windows') + + local logfile = 'Xchdir_fail_log' + clear({ env = { NVIM_LOG_FILE = logfile } }) + + local dir = 'Xtest_not_executable_dir' + mkdir(dir) + finally(function() + rmdir(dir) + n.check_close() + os.remove(logfile) + end) + fn.setfperm(dir, 'rw-------') + + n.exec(([[ + let s:chan = jobstart(['pwd'], {'cwd': '%s', 'pty': v:true}) + let g:status = jobwait([s:chan], 1000)[0] + ]]):format(dir)) + eq(122, eval('g:status')) + t.assert_log(('chdir%%(%s%%) failed: permission denied'):format(dir), logfile, 100) end) it('returns 0 when it fails to start', function()