Commit: patch 9.2.1026: heap-use-after-free via DiffUpdated autocommand

2 views
Skip to first unread message

Christian Brabandt

unread,
Sep 1, 2026, 3:00:18 PM (3 days ago) Sep 1
to vim...@googlegroups.com
patch 9.2.1026: heap-use-after-free via DiffUpdated autocommand

Commit: https://github.com/vim/vim/commit/d81720e01a7ce79afa2c55aff5270d9f394ccbbe
Author: Christian Brabandt <c...@256bit.org>
Date: Tue Sep 1 18:41:39 2026 +0000

patch 9.2.1026: heap-use-after-free via DiffUpdated autocommand

Problem: A DiffUpdated autococmd wiping the current buffer
can cause a use-after-free (Evaopo).
Solution: Disallow changing the window layout while DiffUpdated
autocommand runs.

closes: #21177

Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 7a1df5c46..4c7d7922d 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -1,4 +1,4 @@
-*autocmd.txt* For Vim version 9.2. Last change: 2026 Aug 04
+*autocmd.txt* For Vim version 9.2. Last change: 2026 Sep 01


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -812,6 +812,7 @@ DiffUpdated After diffs have been updated. Depending on
what kind of diff is being used (internal or
external) this can be triggered on every
change or when doing |:diffupdate|.
+ It is not allowed to change the window layout.
*DirChangedPre*
DirChangedPre The working directory is going to be changed,
as with |DirChanged|. The pattern is like
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index bbc857393..e352e9c20 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.2. Last change: 2026 Aug 25
+*version9.txt* For Vim version 9.2. Last change: 2026 Sep 01


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52710,6 +52710,8 @@ Changed ~
- |complete_info()| can distinguish between manual and automatic triggered
completions via the "auto" item.
- fold functions take an optional {winid} parameter.
+- It is no longer allowed to change the window layout during a |DiffUpdated|
+ autocommand.

*added-9.3*
Added ~
diff --git a/src/diff.c b/src/diff.c
index 4836922c9..ae5bdb1d9 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1191,7 +1191,9 @@ theend:
if (had_diffs || curtab->tp_first_diff != NULL)
{
diff_redraw(TRUE);
+ window_layout_lock();
apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
+ window_layout_unlock();
}
}

@@ -4444,7 +4446,9 @@ theend:
{
// Also need to redraw the other buffers.
diff_redraw(FALSE);
+ window_layout_lock();
apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
+ window_layout_unlock();
}
}

diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 7165e19d8..6b4dccb7f 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
@@ -3671,4 +3671,35 @@ func Test_diff_cursorbind_after_undo()
%bw!
endfunc

+func Test_diffupdated_close_window_fails()
+ new
+ only
+ call setline(1, ['one', 'two', 'three'])
+ let w1 = win_getid()
+ vnew
+ call setline(1, ['one', 'Two', 'three'])
+ windo diffthis
+ call win_gotoid(w1)
+
+ augroup TestDiffUpdated
+ autocmd!
+ autocmd DiffUpdated * bw!
+ augroup END
+
+ try
+ diffupdate
+ catch
+ endtry
+
+ augroup TestDiffUpdated
+ autocmd!
+ augroup END
+ augroup! TestDiffUpdated
+
+ call assert_equal(2, winnr('$'))
+
+ diffoff!
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 2356bb87a..72f896875 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1026,
/**/
1025,
/**/
Reply all
Reply to author
Forward
0 new messages