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 #8769)
diff --git a/src/tag.c b/src/tag.c
index d729c46..2e57095 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -3878,23 +3878,27 @@
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 @@
// "<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;
}
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
index 92af0d0..ba55159 100644
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -606,6 +606,16 @@
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&
diff --git a/src/version.c b/src/version.c
index e064df3..dfe949d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3362,
+/**/
3361,
/**/
3360,