neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit aed1f8c37730103a38f7248f22826892cd6f556e
parent 1629493f72e8b839cbe039cc99f5a49729e96e8a
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Mon, 12 Jan 2026 07:04:36 +0800

vim-patch:9.1.2079: use-after-free with 'qftf' wiping buffer (#37364)

Problem:  use-after-free with 'quickfixtextfunc' wiping buffer
          (henices)
Solution: Evaluate 'quickfixtextfunc' with textlock enabled.

closes: vim/vim#19142

https://github.com/vim/vim/commit/300ea1133fba310ae8acd7fadc3ab3cc24e8402f

Co-authored-by: Christian Brabandt <cb@256bit.org>
Diffstat:
Mruntime/doc/options.txt | 3+++
Mruntime/lua/vim/_meta/options.lua | 3+++
Msrc/nvim/options.lua | 3+++
Msrc/nvim/quickfix.c | 2++
Mtest/old/testdir/test_quickfix.vim | 23+++++++++++++++++++++++
5 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt @@ -4897,6 +4897,9 @@ A jump table for the options with a short description can be found at |Q_op|. |lambda| or a |Funcref|. See |option-value-function| for more information. + It is not allowed to change text or jump to another window while + evaluating 'qftf' |textlock|. + This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua @@ -5115,6 +5115,9 @@ vim.go.pyx = vim.go.pyxversion --- `lambda` or a `Funcref`. See `option-value-function` for more --- information. --- +--- It is not allowed to change text or jump to another window while +--- evaluating 'qftf' `textlock`. +--- --- This option cannot be set from a `modeline` or in the `sandbox`, for --- security reasons. --- diff --git a/src/nvim/options.lua b/src/nvim/options.lua @@ -6729,6 +6729,9 @@ local options = { |lambda| or a |Funcref|. See |option-value-function| for more information. + It is not allowed to change text or jump to another window while + evaluating 'qftf' |textlock|. + This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. ]=], diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c @@ -4327,6 +4327,7 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, int start_idx, int e args[0].v_type = VAR_DICT; args[0].vval.v_dict = dict; + textlock++; if (callback_call(cb, 1, args, &rettv)) { if (rettv.v_type == VAR_LIST) { qftf_list = rettv.vval.v_list; @@ -4334,6 +4335,7 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, int start_idx, int e } tv_clear(&rettv); } + textlock--; tv_dict_unref(dict); } diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim @@ -6991,4 +6991,27 @@ func Test_quickfix_restore_current_win() bw! Xb endfunc +func Test_quickfixtextfunc_wipes_buffer() + let g:crash="" + new + fu QFexpr(dummy) + bw + endfu + try + set quickfixtextfunc=QFexpr + lad "['0:4:e']" + lw + catch /^Vim\%((\S\+)\)\=:E565:/ + let g:crash='caught' + endtry + " close location list window + bw + delfunc QFexpr + set quickfixtextfunc= + call assert_equal('caught', g:crash) + unlet g:crash + " close the newly opened window + bw +endfunc + " vim: shiftwidth=2 sts=2 expandtab