diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 1aaf66fb65..80acabc51d 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1541,8 +1541,9 @@ void edit_unputchar(void) // Called when p_dollar is set: display a '$' at the end of the changed text // Only works when cursor is in the line that changes. -void display_dollar(colnr_T col) +void display_dollar(colnr_T col_arg) { + colnr_T col = col_arg < 0 ? 0 : col_arg; colnr_T save_col; if (!redrawing()) { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 78450859ac..843854799b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -126,6 +126,7 @@ typedef struct command_line_state { int break_ctrl_c; expand_T xpc; long *b_im_ptr; + buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid } CommandLineState; typedef struct cmdpreview_undo_info { @@ -746,7 +747,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea } else { s->b_im_ptr = &curbuf->b_p_imsearch; } - + s->b_im_ptr_buf = curbuf; if (*s->b_im_ptr == B_IMODE_LMAP) { State |= MODE_LANGMAP; } @@ -1548,20 +1549,21 @@ static int command_line_erase_chars(CommandLineState *s) /// language :lmap mappings and/or Input Method. static void command_line_toggle_langmap(CommandLineState *s) { + long *b_im_ptr = buf_valid(s->b_im_ptr_buf) ? s->b_im_ptr : NULL; if (map_to_exists_mode("", MODE_LANGMAP, false)) { // ":lmap" mappings exists, toggle use of mappings. State ^= MODE_LANGMAP; - if (s->b_im_ptr != NULL) { + if (b_im_ptr != NULL) { if (State & MODE_LANGMAP) { - *s->b_im_ptr = B_IMODE_LMAP; + *b_im_ptr = B_IMODE_LMAP; } else { - *s->b_im_ptr = B_IMODE_NONE; + *b_im_ptr = B_IMODE_NONE; } } } - if (s->b_im_ptr != NULL) { - if (s->b_im_ptr == &curbuf->b_p_iminsert) { + if (b_im_ptr != NULL) { + if (b_im_ptr == &curbuf->b_p_iminsert) { set_iminsert_global(curbuf); } else { set_imsearch_global(curbuf); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index ba9dc88014..3f6443de66 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -106,6 +106,9 @@ static int VIsual_mode_orig = NUL; // saved Visual mode # include "normal.c.generated.h" #endif +static const char e_cmdline_window_already_open[] + = N_("E1292: Command-line window is already open"); + static inline void normal_state_init(NormalState *s) { memset(s, 0, sizeof(NormalState)); @@ -6384,6 +6387,10 @@ static void nv_record(cmdarg_T *cap) } if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') { + if (cmdwin_type != 0) { + emsg(_(e_cmdline_window_already_open)); + return; + } stuffcharReadbuff(cap->nchar); stuffcharReadbuff(K_CMDWIN); } else { diff --git a/src/nvim/window.c b/src/nvim/window.c index 59b6c49eaa..7d99aafa5e 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2306,6 +2306,9 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } if (hnc) { // add next_curwin size next_curwin_size -= (int)p_wiw - (m - n); + if (next_curwin_size < 0) { + next_curwin_size = 0; + } new_size += next_curwin_size; room -= new_size - next_curwin_size; } else { @@ -6695,7 +6698,8 @@ static int win_border_width(win_T *wp) /// Set the width of a window. void win_new_width(win_T *wp, int width) { - wp->w_width = width; + // Should we give an error if width < 0? + wp->w_width = width < 0 ? 0 : width; wp->w_pos_changed = true; win_set_inner_size(wp, true); } diff --git a/test/old/testdir/test_cmdwin.vim b/test/old/testdir/test_cmdwin.vim new file mode 100644 index 0000000000..f948d46be1 --- /dev/null +++ b/test/old/testdir/test_cmdwin.vim @@ -0,0 +1,67 @@ +" Tests for editing the command line. + +source check.vim +source screendump.vim + + +func Test_cant_open_cmdwin_in_cmdwin() + try + call feedkeys("q:q::q\", "x!") + catch + let caught = v:exception + endtry + call assert_match('E1292:', caught) +endfunc + +func Test_cmdwin_virtual_edit() + enew! + set ve=all cpo+=$ + silent normal q/s + + set ve= cpo-=$ +endfunc + +" Check that a :normal command can be used to stop Visual mode without side +" effects. +func Test_normal_escape() + call feedkeys("q:i\" foo\:normal! \\\:\" bar\", 'ntx') + call assert_equal('" bar', @:) +endfunc + +" This was using a pointer to a freed buffer +func Test_cmdwin_freed_buffer_ptr() + " this does not work on MS-Windows because renaming an open file fails + CheckNotMSWindows + + au BufEnter * next 0| file + edit 0 + silent! norm q/ + + au! BufEnter + bwipe! +endfunc + +" This was resulting in a window with negative width. +" The test doesn't reproduce the illegal memory access though... +func Test_cmdwin_split_often() + let lines = &lines + let columns = &columns + set t_WS= + + try + " set encoding=iso8859 + set ruler + winsize 0 0 + noremap 0 H + sil norm 0000000q: + catch /E36:/ + endtry + + bwipe! + set encoding=utf8 + let &lines = lines + let &columns = columns +endfunc + + +" vim: shiftwidth=2 sts=2 expandtab