mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.1.2138: win_execute() and 'autochdir' can corrupt buffer name
Problem: With 'autochdir' win_execute() can corrupt the buffer name,
causing :write to use wrong path.
Solution: Save and restore b_fname when 'autochdir' is active
(Ingo Karkat).
This is caused by a bad interaction of the 'autochdir' behavior,
overriding of the current directory via :lchdir, and the temporary
window switching done by win_execute(), manifesting when e.g. a custom
completion inspects other buffers:
1. In the initial state after the :lcd .. we have curbuf->b_fname =
"Xsubdir/file".
2. do_autochdir() is invoked, temporarily undoing the :lcd .., changing
back into the Xsubdir/ subdirectory.
3. win_execute() switches windows, triggering win_enter_ext() →
win_fix_current_dir() → shorten_fnames(TRUE)
4. shorten_fnames() processes *all* buffers
5. shorten_buf_fname() makes the filename relative to the current
(wrong) directory; b_fname becomes "file" instead of "Xsubdir/file"
6. Directory restoration correctly restores working directory via
mch_chdir() (skipping a second do_autochdir() invocation because
apply_acd is FALSE), but b_fname remains corrupted, with the
"Xsubdir/" part missing.
7. expand("%:p") (and commands like :write) continue to use the
corrupted filename, resolving to a wrong path that's missing the
"Xsubdir/" part.
To fix the problem the short filename is saved if its in effect (i.e.
pointed to by curbuf->b_fname) and 'autochdir' happened. It's then
restored in case of a local cwd override. The conditions limit this
workaround to when 'autochdir' is active *and* overridden by a :lchdir.
closes: #19343
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Ingo Karkat <swdev@ingo-karkat.de>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
a24cb278bd
commit
abb4d74033
@@ -52512,4 +52512,9 @@ Problem: Some tests are not valid on OpenBSD.
|
||||
Solution: Add CheckNotOpenBSD, use it to skip certain tests
|
||||
(Kevin Goodsell).
|
||||
|
||||
Patch 9.1.2138
|
||||
Problem: With 'autochdir' win_execute() can corrupt the buffer name, causing
|
||||
:write to use wrong path.
|
||||
Solution: Save and restore b_fname when 'autochdir' is active (Ingo Karkat).
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:fdm=manual:nofoldenable
|
||||
|
||||
@@ -732,6 +732,7 @@ f_win_execute(typval_T *argvars, typval_T *rettv)
|
||||
# ifdef FEAT_AUTOCHDIR
|
||||
char_u autocwd[MAXPATHL];
|
||||
int apply_acd = FALSE;
|
||||
char_u *save_sfname = NULL;
|
||||
# endif
|
||||
|
||||
// Getting and setting directory can be slow on some systems, only do
|
||||
@@ -754,6 +755,8 @@ f_win_execute(typval_T *argvars, typval_T *rettv)
|
||||
// apply 'acd' afterwards, otherwise restore the current directory.
|
||||
if (cwd_status == OK && p_acd)
|
||||
{
|
||||
if (curbuf->b_sfname != NULL && curbuf->b_fname == curbuf->b_sfname)
|
||||
save_sfname = vim_strsave(curbuf->b_sfname);
|
||||
do_autochdir();
|
||||
apply_acd = mch_dirname(autocwd, MAXPATHL) == OK
|
||||
&& STRCMP(cwd, autocwd) == 0;
|
||||
@@ -768,11 +771,24 @@ f_win_execute(typval_T *argvars, typval_T *rettv)
|
||||
restore_win_noblock(&switchwin, TRUE);
|
||||
# ifdef FEAT_AUTOCHDIR
|
||||
if (apply_acd)
|
||||
{
|
||||
vim_free(save_sfname);
|
||||
do_autochdir();
|
||||
}
|
||||
else
|
||||
# endif
|
||||
if (cwd_status == OK)
|
||||
{
|
||||
mch_chdir((char *)cwd);
|
||||
# ifdef FEAT_AUTOCHDIR
|
||||
if (save_sfname != NULL)
|
||||
{
|
||||
vim_free(curbuf->b_sfname);
|
||||
curbuf->b_sfname = save_sfname;
|
||||
curbuf->b_fname = curbuf->b_sfname;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
// Update the status line if the cursor moved.
|
||||
if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
|
||||
|
||||
@@ -189,6 +189,27 @@ func Test_lcd_split()
|
||||
quit!
|
||||
endfunc
|
||||
|
||||
" Test that a temporary override of 'autochdir' via :lcd isn't clobbered by win_execute() in a split window.
|
||||
func Test_lcd_win_execute()
|
||||
CheckOption autochdir
|
||||
|
||||
let startdir = getcwd()
|
||||
call mkdir('Xsubdir', 'R')
|
||||
call test_autochdir()
|
||||
set autochdir
|
||||
edit Xsubdir/file
|
||||
call assert_match('testdir.Xsubdir.file$', expand('%:p'))
|
||||
split
|
||||
lcd ..
|
||||
call assert_match('testdir.Xsubdir.file$', expand('%:p'))
|
||||
call win_execute(win_getid(2), "")
|
||||
call assert_match('testdir.Xsubdir.file$', expand('%:p'))
|
||||
|
||||
set noautochdir
|
||||
bwipe!
|
||||
call chdir(startdir)
|
||||
endfunc
|
||||
|
||||
func Test_cd_from_non_existing_dir()
|
||||
CheckNotMSWindows
|
||||
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2138,
|
||||
/**/
|
||||
2137,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user