fix: segfault in find_tagfunc_tags #18841

fixes #15221

I tried to reproduce with a test, but failed. The below patch is able to
cause the out of bound access (I verified by adding a check to the
code), but it doesn't seg fault or trigger asan/valgrind errors.

```
diff --git a/src/nvim/testdir/test_tagfunc.vim b/src/nvim/testdir/test_tagfunc.vim
index ffc1d63b9..22828a39f 100644
--- a/src/nvim/testdir/test_tagfunc.vim
+++ b/src/nvim/testdir/test_tagfunc.vim
@@ -117,4 +117,26 @@ func Test_tagfunc_settagstack()
   delfunc Mytagfunc2
 endfunc

+func Test_tagfunc_settagstack_many()
+
+  func Mytagfunc1(pat, flags, info)
+    return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
+  endfunc
+  set tagfunc=Mytagfunc1
+  call writefile([''], 'Xtest')
+
+  for i in range(0,20)
+    let pos = [bufnr()]  + getcurpos()[1:]
+    let newtag = [{'tagname' : 'mytag' + i, 'from' : pos}]
+    call settagstack(1, {'items' : newtag}, 'a')
+    call settagstack(1, {'curidx' : 21})
+  endfor
+
+  tag
+
+  call delete('Xtest')
+  set tagfunc&
+  delfunc Mytagfunc1
+endfunc
```
This commit is contained in:
fkm3 2022-06-09 08:05:36 -07:00 committed by GitHub
parent 11e0fea8ba
commit bf327368d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1143,7 +1143,15 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl
typval_T args[4];
typval_T rettv;
char_u flagString[4];
taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx];
taggy_T *tag = NULL;
if (curwin->w_tagstacklen > 0) {
if (curwin->w_tagstackidx == curwin->w_tagstacklen) {
tag = &curwin->w_tagstack[curwin->w_tagstackidx - 1];
} else {
tag = &curwin->w_tagstack[curwin->w_tagstackidx];
}
}
if (*curbuf->b_p_tfu == NUL) {
return FAIL;
@ -1156,7 +1164,7 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl
// create 'info' dict argument
dict_T *const d = tv_dict_alloc_lock(VAR_FIXED);
if (tag->user_data != NULL) {
if (tag != NULL && tag->user_data != NULL) {
tv_dict_add_str(d, S_LEN("user_data"), (const char *)tag->user_data);
}
if (buf_ffname != NULL) {