]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0708: Leaks in do_autocmd in error case v9.2.0708
authorChristian Brabandt <cb@256bit.org>
Tue, 23 Jun 2026 19:44:48 +0000 (19:44 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 23 Jun 2026 19:46:52 +0000 (19:46 +0000)
Problem:  Leak in do_autocmd in error case (Cheng)
Solution: goto err_exit in the error case and clean up, make the double
          ++once an actual error

closes: #20606

Signed-off-by: Christian Brabandt <cb@256bit.org>
src/autocmd.c
src/testdir/test_autocmd.vim
src/version.c

index 2e7f1efd01920c329ba389903b755ad27b1e2cc3..98014cf03746fafc857505ef64b42cb0dc3b512f 100644 (file)
@@ -1025,7 +1025,10 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
            if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
            {
                if (once)
+               {
                    semsg(_(e_duplicate_argument_str), "++once");
+                   goto err_exit;
+               }
                once = TRUE;
                cmd = skipwhite(cmd + 6);
            }
@@ -1036,7 +1039,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
                if (nested)
                {
                    semsg(_(e_duplicate_argument_str), "++nested");
-                   return;
+                   goto err_exit;
                }
                nested = TRUE;
                cmd = skipwhite(cmd + 8);
@@ -1051,12 +1054,12 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
                    // be removed and "nested" accepted as the start of the
                    // command.
                    emsg(_(e_invalid_command_nested_did_you_mean_plusplus_nested));
-                   return;
+                   goto err_exit;
                }
                if (nested)
                {
                    semsg(_(e_duplicate_argument_str), "nested");
-                   return;
+                   goto err_exit;
                }
                nested = TRUE;
                cmd = skipwhite(cmd + 6);
@@ -1075,7 +1078,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
 
            cmd = expand_sfile(cmd);
            if (cmd == NULL)        // some error
-               return;
+               goto err_exit;
            cmd_need_free = TRUE;
        }
     }
@@ -1111,6 +1114,7 @@ do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
                break;
     }
 
+err_exit:
     if (cmd_need_free)
        vim_free(cmd);
     vim_free(tofree);
index 54116a5857fff08b68845ddd6047237eb9795e10..4828b3ea9e1950bd037b19a2aaf88fa6d3dd8366 100644 (file)
@@ -3208,8 +3208,41 @@ func Test_autocmd_once()
   close
 
   call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+  call assert_false(exists('#WinNew'))
 endfunc
 
+func Test_autocmd_dup_arg()
+       " Duplicate ++once / ++nested, or the legacy "nested" used twice, must
+       " error out *and* not create the autocommand.  Using an environment
+       " variable in the pattern also exercises the error-exit path that frees
+       " the expanded pattern (checked by the address/leak sanitizers).
+       augroup XdupTest
+               au!
+       augroup END
+       let $XAUTODIR = 'Xfoo'
+
+       " New behavior: duplicate ++once now aborts, the autocmd is not added
+       call assert_fails('au XdupTest WinNew $XAUTODIR/* ++once ++once echo bad', 'E983:')
+       call assert_false(exists('#XdupTest#WinNew'))
+
+       call assert_fails('au XdupTest WinNew $XAUTODIR/* ++nested ++nested echo bad', 'E983:')
+       call assert_false(exists('#XdupTest#WinNew'))
+
+       call assert_fails('au XdupTest WinNew $XAUTODIR/* nested nested echo bad', 'E983:')
+       call assert_false(exists('#XdupTest#WinNew'))
+
+       " "nested" without "++" is rejected in Vim9 script (also frees the pattern)
+       call assert_fails('vim9cmd au XdupTest WinNew $XAUTODIR/* nested echo bad', 'E1078:')
+       call assert_false(exists('#XdupTest#WinNew'))
+
+       augroup XdupTest
+       au!
+       augroup END
+       augroup! XdupTest
+       let $XAUTODIR = ''
+endfunc
+
+
 func Test_autocmd_bufreadpre()
   new
   let b:bufreadpre = 1
index ff0e68e1c77d16fb542cccb2f29aa7042c8b9b11..753a36d2de375f69af3a7179babbfbd81186aaf6 100644 (file)
@@ -759,6 +759,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    708,
 /**/
     707,
 /**/