changeset 25652:ca61340ac1b9 v8.2.3362

patch 8.2.3362: buffer overflow when completing long tag name Commit: https://github.com/vim/vim/commit/489d60996deb5e7c1a3b4633412d54632e6def42 Author: Gregory Anders <greg@gpanders.com> Date: Sat Aug 21 16:21:19 2021 +0200 patch 8.2.3362: buffer overflow when completing long tag name Problem: Buffer overflow when completing long tag name. Solution: Allocate the buffer dynamically. (Gregory Anders, closes https://github.com/vim/vim/issues/8769)
author Bram Moolenaar <Bram@vim.org>
date Sat, 21 Aug 2021 16:30:04 +0200
parents 3066656a3860
children dc3b761cc059
files src/tag.c src/testdir/test_tagjump.vim src/version.c
diffstat 3 files changed, 51 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/tag.c
+++ b/src/tag.c
@@ -3878,23 +3878,27 @@ expand_tags(
     char_u	***file)
 {
     int		i;
-    int		c;
-    int		tagnmflag;
-    char_u      tagnm[100];
+    int		extra_flag;
+    char_u	*name_buf;
+    size_t	name_buf_size = 100;
     tagptrs_T	t_p;
     int		ret;
 
+    name_buf = alloc(name_buf_size);
+    if (name_buf == NULL)
+	return FAIL;
+
     if (tagnames)
-	tagnmflag = TAG_NAMES;
+	extra_flag = TAG_NAMES;
     else
-	tagnmflag = 0;
+	extra_flag = 0;
     if (pat[0] == '/')
 	ret = find_tags(pat + 1, num_file, file,
-		TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NO_TAGFUNC,
+		TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC,
 		TAG_MANY, curbuf->b_ffname);
     else
 	ret = find_tags(pat, num_file, file,
-	      TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NO_TAGFUNC | TAG_NOIC,
+	      TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC | TAG_NOIC,
 		TAG_MANY, curbuf->b_ffname);
     if (ret == OK && !tagnames)
     {
@@ -3902,18 +3906,37 @@ expand_tags(
 	 // "<tagname>\0<kind>\0<filename>\0"
 	 for (i = 0; i < *num_file; i++)
 	 {
+	     size_t	len;
+
 	     parse_match((*file)[i], &t_p);
-	     c = (int)(t_p.tagname_end - t_p.tagname);
-	     mch_memmove(tagnm, t_p.tagname, (size_t)c);
-	     tagnm[c++] = 0;
-	     tagnm[c++] = (t_p.tagkind != NULL && *t_p.tagkind)
-							 ? *t_p.tagkind : 'f';
-	     tagnm[c++] = 0;
-	     mch_memmove((*file)[i] + c, t_p.fname, t_p.fname_end - t_p.fname);
-	     (*file)[i][c + (t_p.fname_end - t_p.fname)] = 0;
-	     mch_memmove((*file)[i], tagnm, (size_t)c);
+	     len = t_p.tagname_end - t_p.tagname;
+	     if (len > name_buf_size - 3)
+	     {
+		 char_u *buf;
+
+		 name_buf_size = len + 3;
+		 buf = vim_realloc(name_buf, name_buf_size);
+		 if (buf == NULL)
+		 {
+		     vim_free(name_buf);
+		     return FAIL;
+		 }
+		 name_buf = buf;
+	     }
+
+	     mch_memmove(name_buf, t_p.tagname, len);
+	     name_buf[len++] = 0;
+	     name_buf[len++] = (t_p.tagkind != NULL && *t_p.tagkind)
+							  ? *t_p.tagkind : 'f';
+	     name_buf[len++] = 0;
+	     mch_memmove((*file)[i] + len, t_p.fname,
+						    t_p.fname_end - t_p.fname);
+	     (*file)[i][len + (t_p.fname_end - t_p.fname)] = 0;
+	     mch_memmove((*file)[i], name_buf, len);
 	}
     }
+
+    vim_free(name_buf);
     return ret;
 }
 
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -606,6 +606,16 @@ func Test_tag_line_toolong()
   call assert_equal('Xsomewhere', expand('%'))
   call assert_equal(3, getcurpos()[1])
 
+  " expansion on command line works with long lines when &wildoptions contains
+  " 'tagfile'
+  set wildoptions=tagfile
+  call writefile([
+	\ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa	file	/^pattern$/;"	f'
+	\ ], 'Xtags')
+  call feedkeys(":tag \<Tab>", 'tx')
+  " Should not crash
+  call assert_true(v:true)
+
   call delete('Xtags')
   call delete('Xsomewhere')
   set tags&
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3362,
+/**/
     3361,
 /**/
     3360,