From 0c70fbf0d6393d7ba3e617619d7d469366633199 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 12 Dec 2025 23:34:07 -0500 Subject: [PATCH 1/6] vim-patch:8.2.4633: Visual range does not work before command modifiers Problem: Visual range does not work before command modifiers. Solution: Move Visual range to after command modifiers. https://github.com/vim/vim/commit/c75bca3ee955ff36ece99a42041733ddea5f45a7 Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 21 +++++++++++++++++++++ test/old/testdir/test_source.vim | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index fc6d188f8a..8c5f1b74f1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2511,8 +2511,19 @@ static char *ex_range_without_command(exarg_T *eap) /// @return FAIL when the command is not to be executed. int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only) { + char *cmd_start; + bool has_visual_range = false; CLEAR_POINTER(cmod); + if (strncmp(eap->cmd, "'<,'>", 5) == 0) { + // The automatically inserted Visual area range is skipped, so that + // typing ":cmdmod cmd" in Visual mode works without having to move the + // range to after the modififiers. + eap->cmd += 5; + cmd_start = eap->cmd; + has_visual_range = true; + } + // Repeat until no more command modifiers are found. while (true) { while (*eap->cmd == ' ' @@ -2750,6 +2761,16 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, break; } + if (has_visual_range && eap->cmd > cmd_start) { + // Move the '<,'> range to after the modifiers and insert a colon. + // Since the modifiers have been parsed put the colon on top of the + // space: "'<,'>mod cmd" -> "mod:'<,'>cmd + // Put eap->cmd after the colon. + memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); + eap->cmd -= 5; + memmove(eap->cmd - 1, ":'<,'>", 6); + } + return OK; } diff --git a/test/old/testdir/test_source.vim b/test/old/testdir/test_source.vim index 733daaaf78..11135268a5 100644 --- a/test/old/testdir/test_source.vim +++ b/test/old/testdir/test_source.vim @@ -577,6 +577,13 @@ func Test_source_buffer_vim9() call assert_equal(#{pi: 3.12, e: 2.71828}, g:Math) call assert_equal(['vim', 'nano'], g:Editors) + " '<,'> range before the cmd modifier works + unlet g:Math + unlet g:Editors + exe "normal 6GV4j:vim9cmd source\" + call assert_equal(['vim', 'nano'], g:Editors) + unlet g:Editors + " test for using try/catch %d _ let lines =<< trim END From 78292dcc3d0e94d1413af8f2417227377ca5dc26 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 12 Dec 2025 23:40:11 -0500 Subject: [PATCH 2/6] vim-patch:8.2.4636: not using Visual range Problem: Not using Visual range. Solution: Put the command pointer back to the range. https://github.com/vim/vim/commit/1501b63f8dedbd15ee5bfd9a177e558ffdf0673a Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8c5f1b74f1..24dcc76b19 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2761,14 +2761,19 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, break; } - if (has_visual_range && eap->cmd > cmd_start) { - // Move the '<,'> range to after the modifiers and insert a colon. - // Since the modifiers have been parsed put the colon on top of the - // space: "'<,'>mod cmd" -> "mod:'<,'>cmd - // Put eap->cmd after the colon. - memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); - eap->cmd -= 5; - memmove(eap->cmd - 1, ":'<,'>", 6); + if (has_visual_range) { + if (eap->cmd > cmd_start) { + // Move the '<,'> range to after the modifiers and insert a colon. + // Since the modifiers have been parsed put the colon on top of the + // space: "'<,'>mod cmd" -> "mod:'<,'>cmd + // Put eap->cmd after the colon. + memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); + eap->cmd -= 5; + memmove(eap->cmd - 1, ":'<,'>", 6); + } else { + // no modifiers, move the pointer back + eap->cmd -= 5; + } } return OK; From 0fa678c02f569484e43b58253d8304ae5e5d0289 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 12 Dec 2025 23:42:13 -0500 Subject: [PATCH 3/6] vim-patch:8.2.4637: warning for using uninitialized variable Problem: Warning for using uninitialized variable. (Tony Mechelynck) Solution: Initialize it. https://github.com/vim/vim/commit/565d1278cbbb7bc927bee207d5c2bc0bb95928fa Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 24dcc76b19..71927d1450 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2511,7 +2511,7 @@ static char *ex_range_without_command(exarg_T *eap) /// @return FAIL when the command is not to be executed. int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only) { - char *cmd_start; + char *cmd_start = NULL; bool has_visual_range = false; CLEAR_POINTER(cmod); From cd543d618dcf94e1a01f3d498a416e425ab75c23 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 13 Dec 2025 00:33:59 -0500 Subject: [PATCH 4/6] vim-patch:8.2.4763: using invalid pointer with "V:" in Ex mode Problem: Using invalid pointer with "V:" in Ex mode. Solution: Correctly handle the command being changed to "+". https://github.com/vim/vim/commit/f50808ed135ab973296bca515ae4029b321afe47 Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 27 ++++++++++++++++++++++----- test/old/testdir/test_ex_mode.vim | 12 ++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 71927d1450..dac328c51e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2511,7 +2511,9 @@ static char *ex_range_without_command(exarg_T *eap) /// @return FAIL when the command is not to be executed. int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only) { + char *orig_cmd = eap->cmd; char *cmd_start = NULL; + bool did_plus_cmd = false; bool has_visual_range = false; CLEAR_POINTER(cmod); @@ -2537,6 +2539,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, && getline_equal(eap->ea_getline, eap->cookie, getexline) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = exmode_plus; + did_plus_cmd = true; if (!skip_only) { ex_pressedreturn = true; } @@ -2767,12 +2770,26 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, // Since the modifiers have been parsed put the colon on top of the // space: "'<,'>mod cmd" -> "mod:'<,'>cmd // Put eap->cmd after the colon. - memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); - eap->cmd -= 5; - memmove(eap->cmd - 1, ":'<,'>", 6); + if (did_plus_cmd) { + size_t len = strlen(cmd_start); + + // Special case: empty command may have been changed to "+": + // "'<,'>mod" -> "mod'<,'>+ + memmove(orig_cmd, cmd_start, len); + strcpy(orig_cmd + len, "'<,'>+"); + } else { + memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); + eap->cmd -= 5; + memmove(eap->cmd - 1, ":'<,'>", 6); + } } else { - // no modifiers, move the pointer back - eap->cmd -= 5; + // No modifiers, move the pointer back. + // Special case: empty command may have been changed to "+". + if (did_plus_cmd) { + eap->cmd = "'<,'>+"; + } else { + eap->cmd = orig_cmd; + } } } diff --git a/test/old/testdir/test_ex_mode.vim b/test/old/testdir/test_ex_mode.vim index 32b01fef9e..cfe1552f29 100644 --- a/test/old/testdir/test_ex_mode.vim +++ b/test/old/testdir/test_ex_mode.vim @@ -287,6 +287,18 @@ func Test_ex_mode_large_indent() bwipe! endfunc +" This was accessing illegal memory when using "+" for eap->cmd. +func Test_empty_command_visual_mode() + let lines =<< trim END + r + 0norm0V: + :qall! + END + call writefile(lines, 'Xexmodescript') + call assert_equal(1, RunVim([], [], '-u NONE -e -s -S Xexmodescript')) + + call delete('Xexmodescript') +endfunc " Testing implicit print command func Test_implicit_print() From edd99f09c7acc5f0f497746260587674590d0833 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 13 Dec 2025 00:57:57 -0500 Subject: [PATCH 5/6] vim-patch:8.2.5092: using "'<,'>" in Ex mode may compare unrelated pointers Problem: Using "'<,'>" in Ex mode may compare unrelated pointers. Solution: Set eap->cmd to "+" only later. https://github.com/vim/vim/commit/48ce135e6d45e6c10ed0c0fc4cb8433bf647672a Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index dac328c51e..479b6a24cf 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2513,14 +2513,16 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, { char *orig_cmd = eap->cmd; char *cmd_start = NULL; - bool did_plus_cmd = false; + bool use_plus_cmd = false; bool has_visual_range = false; CLEAR_POINTER(cmod); if (strncmp(eap->cmd, "'<,'>", 5) == 0) { // The automatically inserted Visual area range is skipped, so that // typing ":cmdmod cmd" in Visual mode works without having to move the - // range to after the modififiers. + // range to after the modififiers. The command will be + // "'<,'>cmdmod cmd", parse "cmdmod cmd" and then put back "'<,'>" + // before "cmd" below. eap->cmd += 5; cmd_start = eap->cmd; has_visual_range = true; @@ -2534,15 +2536,16 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, eap->cmd++; } - // in ex mode, an empty line works like :+ + // in ex mode, an empty command (after modifiers) works like :+ if (*eap->cmd == NUL && exmode_active && getline_equal(eap->ea_getline, eap->cookie, getexline) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = exmode_plus; - did_plus_cmd = true; + use_plus_cmd = true; if (!skip_only) { ex_pressedreturn = true; } + break; // no modifiers following } // ignore comment and empty lines @@ -2770,11 +2773,11 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, // Since the modifiers have been parsed put the colon on top of the // space: "'<,'>mod cmd" -> "mod:'<,'>cmd // Put eap->cmd after the colon. - if (did_plus_cmd) { + if (use_plus_cmd) { size_t len = strlen(cmd_start); - // Special case: empty command may have been changed to "+": - // "'<,'>mod" -> "mod'<,'>+ + // Special case: empty command uses "+": + // "'<,'>mods" -> "mods'<,'>+ memmove(orig_cmd, cmd_start, len); strcpy(orig_cmd + len, "'<,'>+"); } else { @@ -2784,13 +2787,15 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, } } else { // No modifiers, move the pointer back. - // Special case: empty command may have been changed to "+". - if (did_plus_cmd) { + // Special case: change empty command to "+". + if (use_plus_cmd) { eap->cmd = "'<,'>+"; } else { eap->cmd = orig_cmd; } } + } else if (use_plus_cmd) { + eap->cmd = exmode_plus; } return OK; From 2c560d85447fef540881d24c0f8c68b892aa6e19 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 13 Dec 2025 01:11:25 -0500 Subject: [PATCH 6/6] vim-patch:9.0.0025: accessing beyond allocated memory with the cmdline window Problem: Accessing beyond allocated memory when using the cmdline window in Ex mode. Solution: Use "*" instead of "'<,'>" for Visual mode. https://github.com/vim/vim/commit/c6fdb15d423df22e1776844811d082322475e48a Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 6 ++++-- test/old/testdir/test_cmdline.vim | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 479b6a24cf..cb0ebf0d6e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2777,9 +2777,11 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, size_t len = strlen(cmd_start); // Special case: empty command uses "+": - // "'<,'>mods" -> "mods'<,'>+ + // "'<,'>mods" -> "mods *+ + // Use "*" instead of "'<,'>" to avoid the command getting + // longer, in case is was allocated. memmove(orig_cmd, cmd_start, len); - strcpy(orig_cmd + len, "'<,'>+"); + xmemcpyz(orig_cmd + len, S_LEN(" *+")); } else { memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); eap->cmd -= 5; diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index f5955a58cf..0a2b7b6141 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -2561,6 +2561,14 @@ func Test_cmdwin_insert_mode_close() call assert_equal(1, winnr('$')) endfunc +func Test_cmdwin_ex_mode_with_modifier() + " this was accessing memory after allocated text in Ex mode + new + call setline(1, ['some', 'text', 'lines']) + silent! call feedkeys("gQnormal vq:atopleft\\\", 'xt') + bwipe! +endfunc + " test that ";" works to find a match at the start of the first line func Test_zero_line_search() new