From 19bbc43947a75b0279f9697f5830a238af337c5b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Mar 2022 12:29:26 +0800 Subject: vim-patch:8.2.4281: using freed memory with :lopen and :bwipe Problem: Using freed memory with :lopen and :bwipe. Solution: Do not use a wiped out buffer. https://github.com/vim/vim/commit/9b4a80a66544f2782040b641498754bcb5b8d461 Cherry-pick some indent changes from patch 8.2.1432. --- src/nvim/buffer.c | 11 ++- src/nvim/testdir/test_quickfix.vim | 177 ++++++++++++++++++++----------------- 2 files changed, 106 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f200f16a5f..8d042525d3 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1486,8 +1486,15 @@ void set_curbuf(buf_T *buf, int action) // An autocommand may have deleted "buf", already entered it (e.g., when // it did ":bunload") or aborted the script processing! // If curwin->w_buffer is null, enter_buffer() will make it valid again - if ((buf_valid(buf) && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) { - enter_buffer(buf); + bool valid = buf_valid(buf); + if ((valid && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) { + // If the buffer is not valid but curwin->w_buffer is NULL we must + // enter some buffer. Using the last one is hopefully OK. + if (!valid) { + enter_buffer(lastbuf); + } else { + enter_buffer(buf); + } if (old_tw != curbuf->b_p_tw) { check_colorcolumn(curwin); } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 14d13049d9..a00231c5e9 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -796,101 +796,102 @@ func ReadTestProtocol(name) endfunc func Test_locationlist() - enew + enew - augroup testgroup - au! - autocmd BufReadCmd test://* call ReadTestProtocol(expand("")) - augroup END + augroup testgroup + au! + autocmd BufReadCmd test://* call ReadTestProtocol(expand("")) + augroup END - let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ] + let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ] - let qflist = [] - for word in words - call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', }) - " NOTE: problem 1: - " intentionally not setting 'lnum' so that the quickfix entries are not - " valid - eval qflist->setloclist(0, ' ') - endfor + let qflist = [] + for word in words + call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', }) + " NOTE: problem 1: + " intentionally not setting 'lnum' so that the quickfix entries are not + " valid + eval qflist->setloclist(0, ' ') + endfor - " Test A - lrewind - enew - lopen - 4lnext - vert split - wincmd L - lopen - wincmd p - lnext - let fileName = expand("%") - wincmd p - let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '') - let fileName = substitute(fileName, '\\', '/', 'g') - let locationListFileName = substitute(locationListFileName, '\\', '/', 'g') - call assert_equal("test://bar.txt", fileName) - call assert_equal("test://bar.txt", locationListFileName) + " Test A + lrewind + enew + lopen + 4lnext + vert split + wincmd L + lopen + wincmd p + lnext + let fileName = expand("%") + wincmd p + let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '') + let fileName = substitute(fileName, '\\', '/', 'g') + let locationListFileName = substitute(locationListFileName, '\\', '/', 'g') + call assert_equal("test://bar.txt", fileName) + call assert_equal("test://bar.txt", locationListFileName) - wincmd n | only + wincmd n | only - " Test B: - lrewind - lopen - 2 - exe "normal \" - wincmd p - 3 - exe "normal \" - wincmd p - 4 - exe "normal \" - call assert_equal(2, winnr('$')) - wincmd n | only + " Test B: + lrewind + lopen + 2 + exe "normal \" + wincmd p + 3 + exe "normal \" + wincmd p + 4 + exe "normal \" + call assert_equal(2, winnr('$')) + wincmd n | only - " Test C: - lrewind - lopen - " Let's move the location list window to the top to check whether it (the - " first window found) will be reused when we try to open new windows: - wincmd K - 2 - exe "normal \" - wincmd p - 3 - exe "normal \" - wincmd p - 4 - exe "normal \" - 1wincmd w - call assert_equal('quickfix', &buftype) - 2wincmd w - let bufferName = expand("%") - let bufferName = substitute(bufferName, '\\', '/', 'g') - call assert_equal('test://quux.txt', bufferName) + " Test C: + lrewind + lopen + " Let's move the location list window to the top to check whether it (the + " first window found) will be reused when we try to open new windows: + wincmd K + 2 + exe "normal \" + wincmd p + 3 + exe "normal \" + wincmd p + 4 + exe "normal \" + 1wincmd w + call assert_equal('quickfix', &buftype) + 2wincmd w + let bufferName = expand("%") + let bufferName = substitute(bufferName, '\\', '/', 'g') + call assert_equal('test://quux.txt', bufferName) - wincmd n | only + wincmd n | only - augroup! testgroup + augroup! testgroup endfunc func Test_locationlist_curwin_was_closed() - augroup testgroup - au! - autocmd BufReadCmd test_curwin.txt call R(expand("")) - augroup END + augroup testgroup + au! + autocmd BufReadCmd test_curwin.txt call R(expand("")) + augroup END - func! R(n) - quit - endfunc + func! R(n) + quit + endfunc - new - let q = [] - call add(q, {'filename': 'test_curwin.txt' }) - call setloclist(0, q) - call assert_fails('lrewind', 'E924:') + new + let q = [] + call add(q, {'filename': 'test_curwin.txt' }) + call setloclist(0, q) + call assert_fails('lrewind', 'E924:') - augroup! testgroup + augroup! testgroup + delfunc R endfunc func Test_locationlist_cross_tab_jump() @@ -5489,4 +5490,20 @@ func Test_two_qf_windows() %bw! endfunc +" Weird sequence of commands that caused entering a wiped-out buffer +func Test_lopen_bwipe() + func R() + silent! tab lopen + e x + silent! lfile + endfunc + + cal R() + cal R() + cal R() + bw! + delfunc R +endfunc + + " vim: shiftwidth=2 sts=2 expandtab -- cgit From d8b4f3e3b83d5a0fd5d844da34da23c88dc9c4c5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 24 Mar 2022 12:39:31 +0800 Subject: vim-patch:8.2.4327: may end up with no current buffer Problem: May end up with no current buffer. Solution: When deleting the current buffer to not pick a quickfix buffer as the new current buffer. https://github.com/vim/vim/commit/e3537aec2f8d6470010547af28dcbd83d41461b8 The test cannot be ported as-is because Nvim doesn't support "-Z" command line argument. Just use only "--clean" instead. --- src/nvim/buffer.c | 13 +++++++++---- src/nvim/testdir/test_quickfix.vim | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8d042525d3..4ca752e747 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1284,8 +1284,10 @@ int do_buffer(int action, int start, int dir, int count, int forceit) while (jumpidx != curwin->w_jumplistidx) { buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); if (buf != NULL) { - if (buf == curbuf || !buf->b_p_bl) { - buf = NULL; // skip current and unlisted bufs + // Skip current and unlisted bufs. Also skip a quickfix + // buffer, it might be deleted soon. + if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) { + buf = NULL; } else if (buf->b_ml.ml_mfp == NULL) { // skip unloaded buf, but may keep it for later if (bp == NULL) { @@ -1323,7 +1325,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) continue; } // in non-help buffer, try to skip help buffers, and vv - if (buf->b_help == curbuf->b_help && buf->b_p_bl) { + if (buf->b_help == curbuf->b_help && buf->b_p_bl && !bt_quickfix(buf)) { if (buf->b_ml.ml_mfp != NULL) { // found loaded buffer break; } @@ -1343,7 +1345,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } if (buf == NULL) { // No loaded buffer, find listed one FOR_ALL_BUFFERS(buf2) { - if (buf2->b_p_bl && buf2 != curbuf) { + if (buf2->b_p_bl && buf2 != curbuf && !bt_quickfix(buf2)) { buf = buf2; break; } @@ -1355,6 +1357,9 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } else { buf = curbuf->b_prev; } + if (bt_quickfix(buf)) { + buf = NULL; + } } } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index a00231c5e9..5457223677 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -5505,5 +5505,30 @@ func Test_lopen_bwipe() delfunc R endfunc +" Another sequence of commands that caused all buffers to be wiped out +func Test_lopen_bwipe_all() + let lines =<< trim END + func R() + silent! tab lopen + e foo + silent! lfile + endfunc + cal R() + exe "norm \\0" + cal R() + bwipe + + call writefile(['done'], 'Xresult') + qall! + END + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -n -S Xscript') + call assert_equal(['done'], readfile('Xresult')) + endif + + call delete('Xscript') + call delete('Xresult') +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- cgit