From 8d62f5fd58d421edb39b66fd8b350325120b3cd6 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 25 Aug 2021 19:57:18 -0600 Subject: [PATCH] vim-patch:8.2.3362: buffer overflow when completing long tag name (#15449) Problem: Buffer overflow when completing long tag name. Solution: Allocate the buffer dynamically. (Gregory Anders, closes vim/vim#8769) https://github.com/vim/vim/commit/489d60996deb5e7c1a3b4633412d54632e6def42 --- src/nvim/tag.c | 51 +++++++++++++++++++------------ src/nvim/testdir/test_tagjump.vim | 10 ++++++ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index a971849f4c..61d48eb4bf 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -3061,24 +3061,26 @@ expand_tags ( ) { 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; - if (tagnames) - tagnmflag = TAG_NAMES; - else - tagnmflag = 0; + name_buf = xmalloc(name_buf_size); + + if (tagnames) { + extra_flag = TAG_NAMES; + } else { + 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) { @@ -3086,18 +3088,29 @@ expand_tags ( * "\0\0\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); - 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; - 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; - 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 = xrealloc(name_buf, name_buf_size); + name_buf = buf; + } + + 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; + 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; + memmove((*file)[i], name_buf, len); } } + xfree(name_buf); return ret; } diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim index b6d9143bc9..0fa7f85f0d 100644 --- a/src/nvim/testdir/test_tagjump.vim +++ b/src/nvim/testdir/test_tagjump.vim @@ -548,6 +548,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 \", 'tx') + " Should not crash + call assert_true(v:true) + call delete('Xtags') call delete('Xsomewhere') set tags&