aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dewar <seandewar@users.noreply.github.com>2022-02-21 10:55:36 +0000
committerSean Dewar <seandewar@users.noreply.github.com>2022-03-14 13:10:20 +0000
commit880d3537d06ef067021c73bc361fa47ab8347992 (patch)
treeb7ae27ab8ed4998babdd12a27b09e472887d85b1
parent895ca52e4c726fd6c2cf6fbbab0d392818337ce7 (diff)
downloadrneovim-880d3537d06ef067021c73bc361fa47ab8347992.tar.gz
rneovim-880d3537d06ef067021c73bc361fa47ab8347992.tar.bz2
rneovim-880d3537d06ef067021c73bc361fa47ab8347992.zip
vim-patch:8.2.4428: crash when switching tabpage while in the cmdline window
Problem: Crash when switching tabpage while in the cmdline window. Solution: Disallow switching tabpage when in the cmdline window. https://github.com/vim/vim/commit/0f6e28f686dbb59ab3b562408ab9b2234797b9b1 Ensure cmdline window doesn't stop us from closing tabs with EXITFREE. mem_free_all -> win_free_all -> tabpage_close -> ... -> goto_tabpage_tp -> CHECK_CMDWIN can cause an infinite loop if Nvim is exited without using standard methods such as :qa! and friends (e.g: killed via a signal). This issue had caused the ASAN CI's functionaltests to timeout. Cherry-pick Test_cmdwin_tabpage from v8.2.4463. https://github.com/vim/vim/commit/38b85cb4d7216705058708bacbc25ab90cd61595 This bug was already fixed in Nvim. Note that g<Tab> inside cmdwin is already tested for in tabnewentered_spec.lua anyway. E492 is thrown after E11 when using ":norm" in assert_fails for some reason (except after v8.2.1919, which isn't ported yet). As v8.2.1183 isn't ported yet, so we cannot assert E11 directly. Modify the test to check for E11 and E492 seperately; when v8.2.1183 is ported, the assertion for E492 will fail and the changes can be reverted to match upstream. Remove redundant CHECK_CMDWIN from goto_tabpage; it's handled with text_locked() and text_locked_msg() above: vim-patch:8.2.4434: duplicate check for cmdline window Problem: Duplicate check for cmdline window. Solution: Remove the second check. (Sean Dewar, closes vim/vim#9816) https://github.com/vim/vim/commit/16b51d26fe2cc3afb09afd439069220dea74581d
-rw-r--r--src/nvim/eval.c7
-rw-r--r--src/nvim/ex_docmd.c9
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/memory.c3
-rw-r--r--src/nvim/testdir/test_cmdline.vim12
-rw-r--r--src/nvim/window.c16
6 files changed, 39 insertions, 10 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 18b9039d60..b2ce15fd87 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -3257,9 +3257,7 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// b: variables
- // In cmdwin, the alternative buffer should be used.
- hashtab_T *ht
- = is_in_cmdwin() ? &prevwin->w_buffer->b_vars->dv_hashtab : &curbuf->b_vars->dv_hashtab;
+ const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
if (bdone < ht->ht_used) {
if (bdone++ == 0) {
hi = ht->ht_array;
@@ -3273,8 +3271,7 @@ char_u *get_user_var_name(expand_T *xp, int idx)
}
// w: variables
- // In cmdwin, the alternative window should be used.
- ht = is_in_cmdwin() ? &prevwin->w_vars->dv_hashtab : &curwin->w_vars->dv_hashtab;
+ ht = &prevwin_curwin()->w_vars->dv_hashtab;
if (wdone < ht->ht_used) {
if (wdone++ == 0) {
hi = ht->ht_array;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 63dc1e539e..6bd465e6ee 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2704,7 +2704,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *
// only full match global is accepted.
// Look for buffer-local user commands first, then global ones.
- gap = is_in_cmdwin() ? &prevwin->w_buffer->b_ucmds : &curbuf->b_ucmds;
+ gap = &prevwin_curwin()->w_buffer->b_ucmds;
for (;;) {
for (j = 0; j < gap->ga_len; j++) {
uc = USER_CMD_GA(gap, j);
@@ -5378,7 +5378,7 @@ static void uc_list(char_u *name, size_t name_len)
uint32_t a;
// In cmdwin, the alternative buffer should be used.
- garray_T *gap = is_in_cmdwin() ? &prevwin->w_buffer->b_ucmds : &curbuf->b_ucmds;
+ const garray_T *gap = &prevwin_curwin()->w_buffer->b_ucmds;
for (;;) {
for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
@@ -6357,7 +6357,7 @@ char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// In cmdwin, the alternative buffer should be used.
- const buf_T *const buf = is_in_cmdwin() ? prevwin->w_buffer : curbuf;
+ const buf_T *const buf = prevwin_curwin()->w_buffer;
if (idx < buf->b_ucmds.ga_len) {
return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
@@ -6379,7 +6379,8 @@ static char_u *get_user_command_name(int idx, int cmdidx)
}
if (cmdidx == CMD_USER_BUF) {
// In cmdwin, the alternative buffer should be used.
- buf_T *buf = is_in_cmdwin() ? prevwin->w_buffer : curbuf;
+ const buf_T *const buf = prevwin_curwin()->w_buffer;
+
if (idx < buf->b_ucmds.ga_len) {
return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 30287cd6f2..f52f3afe7d 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -6589,7 +6589,7 @@ static int open_cmdwin(void)
/// @return true if in the cmdwin, not editing the command line.
bool is_in_cmdwin(void)
- FUNC_ATTR_PURE
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return cmdwin_type != 0 && get_cmdline_type() == NUL;
}
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index d68ca6b62e..373693a6fe 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -575,6 +575,9 @@ void free_all_mem(void)
// Don't want to trigger autocommands from here on.
block_autocmds();
+ // Ensure cmdline window doesn't prevent closing tabs and windows.
+ cmdwin_type = 0;
+
// Close all tabs and windows. Reset 'equalalways' to avoid redraws.
p_ea = false;
if (first_tabpage->tp_next != NULL) {
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index ff4cbe544c..c589d941da 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1123,6 +1123,18 @@ func Test_cmdlineclear_tabenter()
call delete('XtestCmdlineClearTabenter')
endfunc
+func Test_cmdwin_tabpage()
+ tabedit
+ " v8.2.1919 isn't ported yet, so E492 is thrown after E11 here.
+ " v8.2.1183 also isn't ported yet, so we also can't assert E11 directly.
+ " For now, assert E11 and E492 seperately. When v8.2.1183 is ported, the
+ " assert for E492 will fail and this workaround should be removed.
+ " call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
+ call assert_fails("silent norm q/g ", 'E11:')
+ call assert_fails("silent norm q/g :I\<Esc>", 'E492:')
+ tabclose!
+endfunc
+
" test that ";" works to find a match at the start of the first line
func Test_zero_line_search()
new
diff --git a/src/nvim/window.c b/src/nvim/window.c
index d659f60e66..5878a6ba0b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -73,6 +73,15 @@ typedef enum {
static char *m_onlyone = N_("Already only one window");
+/// @return the current window, unless in the cmdline window and "prevwin" is
+/// set, then return "prevwin".
+win_T *prevwin_curwin(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // In cmdwin, the alternative buffer should be used.
+ return is_in_cmdwin() && prevwin != NULL ? prevwin : curwin;
+}
+
/// all CTRL-W window commands are handled here, called from normal_cmd().
///
/// @param xchar extra char from ":wincmd gx" or NUL
@@ -3857,6 +3866,11 @@ int win_new_tabpage(int after, char_u *filename)
tabpage_T *newtp;
int n;
+ if (cmdwin_type != 0) {
+ emsg(_(e_cmdwin));
+ return FAIL;
+ }
+
newtp = alloc_tabpage();
// Remember the current windows in this Tab page.
@@ -4255,6 +4269,8 @@ void goto_tabpage(int n)
/// @param trigger_leave_autocmds when true trigger *Leave autocommands.
void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_leave_autocmds)
{
+ CHECK_CMDWIN;
+
// Don't repeat a message in another tab page.
set_keep_msg(NULL, 0);