changeset 12680:429bf1b9292f v8.0.1218

patch 8.0.1218: writing to freed memory in autocmd commit https://github.com/vim/vim/commit/8d84ff1a3c8cfe59399d3f675ec080066582fdb6 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Oct 26 16:42:16 2017 +0200 patch 8.0.1218: writing to freed memory in autocmd Problem: Writing to freed memory in autocmd. Solution: Make a copy of the tag line. (Dominique Pelle, closes https://github.com/vim/vim/issues/2245)
author Christian Brabandt <cb@256bit.org>
date Thu, 26 Oct 2017 16:45:05 +0200
parents 9b185c69b714
children ebdb4ea1386e
files src/tag.c src/testdir/test_autocmd.vim src/version.c
diffstat 3 files changed, 54 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/tag.c
+++ b/src/tag.c
@@ -2950,6 +2950,25 @@ test_for_static(tagptrs_T *tagp)
 }
 
 /*
+ * Returns the length of a matching tag line.
+ */
+    static size_t
+matching_line_len(char_u *lbuf)
+{
+    char_u	*p = lbuf + 1;
+
+    /* does the same thing as parse_match() */
+    p += STRLEN(p) + 2;
+#ifdef FEAT_EMACS_TAGS
+    if (*p)
+	p += STRLEN(p);
+    else
+	++p;
+#endif
+    return (p - lbuf) + STRLEN(p);
+}
+
+/*
  * Parse a line from a matching tag.  Does not change the line itself.
  *
  * The line that we get looks like this:
@@ -3071,7 +3090,7 @@ tag_full_fname(tagptrs_T *tagp)
  */
     static int
 jumpto_tag(
-    char_u	*lbuf,		/* line from the tags file for this tag */
+    char_u	*lbuf_arg,	/* line from the tags file for this tag */
     int		forceit,	/* :ta with ! */
     int		keep_help)	/* keep help flag (FALSE for cscope) */
 {
@@ -3079,7 +3098,6 @@ jumpto_tag(
     int		save_magic;
     int		save_p_ws, save_p_scs, save_p_ic;
     linenr_T	save_lnum;
-    int		csave = 0;
     char_u	*str;
     char_u	*pbuf;			/* search pattern buffer */
     char_u	*pbuf_end;
@@ -3099,18 +3117,26 @@ jumpto_tag(
 #ifdef FEAT_FOLDING
     int		old_KeyTyped = KeyTyped;    /* getting the file may reset it */
 #endif
+    size_t	len;
+    char_u	*lbuf;
+
+    /* Make a copy of the line, it can become invalid when an autocommand calls
+     * back here recursively. */
+    len = matching_line_len(lbuf_arg) + 1;
+    lbuf = alloc((int)len);
+    if (lbuf != NULL)
+	mch_memmove(lbuf, lbuf_arg, len);
 
     pbuf = alloc(LSIZE);
 
     /* parse the match line into the tagp structure */
-    if (pbuf == NULL || parse_match(lbuf, &tagp) == FAIL)
+    if (pbuf == NULL || lbuf == NULL || parse_match(lbuf, &tagp) == FAIL)
     {
 	tagp.fname_end = NULL;
 	goto erret;
     }
 
     /* truncate the file name, so it can be used as a string */
-    csave = *tagp.fname_end;
     *tagp.fname_end = NUL;
     fname = tagp.fname;
 
@@ -3246,7 +3272,10 @@ jumpto_tag(
 #endif
 	    keep_help_flag = curbuf->b_help;
     }
+
     if (getfile_result == GETFILE_UNUSED)
+	/* Careful: getfile() may trigger autocommands and call jumpto_tag()
+	 * recursively. */
 	getfile_result = getfile(0, fname, NULL, TRUE, (linenr_T)0, forceit);
     keep_help_flag = FALSE;
 
@@ -3441,8 +3470,7 @@ erret:
 #if defined(FEAT_QUICKFIX)
     g_do_tagpreview = 0; /* For next time */
 #endif
-    if (tagp.fname_end != NULL)
-	*tagp.fname_end = csave;
+    vim_free(lbuf);
     vim_free(pbuf);
     vim_free(tofree_fname);
     vim_free(full_fname);
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -249,6 +249,24 @@ func Test_augroup_warning()
   au! VimEnter
 endfunc
 
+func Test_BufReadCmdHelp()
+  " This used to cause access to free memory
+  au BufReadCmd * e +h
+  help
+
+  helpclose
+  au! BufReadCmd
+endfunc
+
+func Test_BufReadCmdHelpJump()
+  " This used to cause access to free memory
+  au BufReadCmd * e +h{
+  help
+
+  helpclose
+  au! BufReadCmd
+endfunc
+
 func Test_augroup_deleted()
   " This caused a crash before E936 was introduced
   augroup x
--- a/src/version.c
+++ b/src/version.c
@@ -762,6 +762,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1218,
+/**/
     1217,
 /**/
     1216,