# HG changeset patch # User Bram Moolenaar # Date 1629556204 -7200 # Node ID ca61340ac1b9022dcdebf4c8283f5c8efcdad40a # Parent 3066656a38608785ec73aa7e92b4233400cf81fb patch 8.2.3362: buffer overflow when completing long tag name Commit: https://github.com/vim/vim/commit/489d60996deb5e7c1a3b4633412d54632e6def42 Author: Gregory Anders 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) diff --git a/src/tag.c b/src/tag.c --- 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( // "\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); - 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 --- 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 \", '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 --- 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,