changeset 31073:df4957f0ccb5 v9.0.0871

patch 9.0.0871: using freed memory when clearing augroup at more prompt Commit: https://github.com/vim/vim/commit/3b014befa006b7224a84d7d58d9603fc261f34cd Author: Bram Moolenaar <Bram@vim.org> Date: Sun Nov 13 17:53:46 2022 +0000 patch 9.0.0871: using freed memory when clearing augroup at more prompt Problem: Using freed memory when clearing augroup at more prompt. Solution: Delay clearing augroup until it's safe. (closes https://github.com/vim/vim/issues/11441)
author Bram Moolenaar <Bram@vim.org>
date Sun, 13 Nov 2022 19:00:05 +0100
parents f6694a9612d2
children a64ca9f84fd3
files src/autocmd.c src/testdir/test_autocmd.vim src/version.c
diffstat 3 files changed, 41 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -296,9 +296,14 @@ show_autocmd(AutoPat *ap, event_T event)
     if (ap->pat == NULL)		// pattern has been removed
 	return;
 
+    // Make sure no info referenced by "ap" is cleared, e.g. when a timer
+    // clears an augroup.  Jump to "theend" after this!
+    // "ap->pat" may be cleared anyway.
+    ++autocmd_busy;
+
     msg_putchar('\n');
     if (got_int)
-	return;
+	goto theend;
     if (event != last_event || ap->group != last_group)
     {
 	if (ap->group != AUGROUP_DEFAULT)
@@ -314,8 +319,12 @@ show_autocmd(AutoPat *ap, event_T event)
 	last_group = ap->group;
 	msg_putchar('\n');
 	if (got_int)
-	    return;
+	    goto theend;
     }
+
+    if (ap->pat == NULL)
+	goto theend;  // timer might have cleared the pattern or group
+
     msg_col = 4;
     msg_outtrans(ap->pat);
 
@@ -328,21 +337,24 @@ show_autocmd(AutoPat *ap, event_T event)
 	    msg_putchar('\n');
 	msg_col = 14;
 	if (got_int)
-	    return;
+	    goto theend;
 	msg_outtrans(ac->cmd);
 #ifdef FEAT_EVAL
 	if (p_verbose > 0)
 	    last_set_msg(ac->script_ctx);
 #endif
 	if (got_int)
-	    return;
+	    goto theend;
 	if (ac->next != NULL)
 	{
 	    msg_putchar('\n');
 	    if (got_int)
-		return;
+		goto theend;
 	}
     }
+
+theend:
+    --autocmd_busy;
 }
 
 /*
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -62,6 +62,7 @@ if has('timers')
     set updatetime=20
     call timer_start(200, 'ExitInsertMode')
     call feedkeys('a', 'x!')
+    sleep 30m
     call assert_equal(1, g:triggered)
     unlet g:triggered
     au! CursorHoldI
@@ -2159,6 +2160,27 @@ func Test_autocmd_user()
   unlet s:res
 endfunc
 
+func Test_autocmd_user_clear_group()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    autocmd! User
+    for i in range(1, 999)
+      exe 'autocmd User ' .. 'Foo' .. i .. ' bar'
+    endfor
+    au CmdlineLeave : call timer_start(0, {-> execute('autocmd! User')})
+  END
+  call writefile(lines, 'XautoUser', 'D')
+  let buf = RunVimInTerminal('-S XautoUser', {'rows': 10})
+
+  " this was using freed memory
+  call term_sendkeys(buf, ":autocmd User\<CR>")
+  call TermWait(buf, 50)
+  call term_sendkeys(buf, "G")
+
+  call StopVimInTerminal(buf)
+endfunc
+
 function s:Before_test_dirchanged()
   augroup test_dirchanged
     autocmd!
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    871,
+/**/
     870,
 /**/
     869,