fix(window): win_move_after UAF from naughty autocmds (#37065)

Problem: use-after-free in win_move_after if win_enter autocommands free win1/2.
Solution: set w_pos_changed before calling win_enter.

(cherry picked from commit d1189ea508, also adding
an import of "exec" in the test)
This commit is contained in:
Sean Dewar
2025-12-21 20:31:05 +00:00
committed by github-actions[bot]
parent 124c18261c
commit 6338d2d54b
2 changed files with 19 additions and 2 deletions

View File

@@ -2071,10 +2071,10 @@ void win_move_after(win_T *win1, win_T *win2)
win_comp_pos(); // recompute w_winrow for all windows
redraw_later(curwin, UPD_NOT_VALID);
}
win_enter(win1, false);
win1->w_pos_changed = true;
win2->w_pos_changed = true;
win_enter(win1, false);
}
/// Compute maximum number of windows that can fit within "height" in frame "fr".

View File

@@ -8,6 +8,7 @@ local dedent = t.dedent
local eq = t.eq
local neq = t.neq
local eval = n.eval
local exec = n.exec
local feed = n.feed
local clear = n.clear
local matches = t.matches
@@ -695,4 +696,20 @@ describe('autocmd', function()
vim.cmd "tabnew"
]]
end)
it('no use-after-free from win_enter autocommands in win_move_after', function()
exec [[
split foo
split bar
lcd ..
wincmd b
]]
eq(fn.winnr('$'), fn.winnr())
-- Using DirChanged as Enter/Leave autocmds are blocked by :ball here.
exec [[
autocmd DirChanged * ++once split flarb | only!
ball
]]
eq('flarb', fn.bufname())
end)
end)