Problem: tests: no test for using shellescape() in combination with :!
Solution: Add a test that checks runtime files for using wrong
combination of shellescape() with ! ex command
This has lead to a few security relevant issues, so add a test that
checks all runtime files for any ! followed by a shellescape() that does
not use the {special} arg.
related: Commit: 3fb5e58fbc63d86a3e65f1a141b0d67af2 (patch 9.2.0479:
[security]: runtime(tar): command injection in tar plugin)
closes: vim/vim#20286
Supported by AI
fccc2adc98
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: quickfix: can set quickfixtextfunc in restricted/sandbox mode
(tacdm)
Solution: Disallow setting the quickfixtextfunc option from a sandbox
and restricted mode (Yegappan Lakshmanan).
closes: vim/vim#20305cb8510d470
Co-Authored-by: tacdm
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Problem: virtualedit=insert doesn't work during change operation
(after 6.1.014).
Solution: Make virtual_op only affect virtualedit=block (zeertzjq).
related: neovim/neovim#35391
closes: vim/vim#202983d0a6073e5
Problem: setline() insert mode mapping may trigger autoindent,
corrupting the newly inserted line content (Evgeni Chasnovski)
Solution: Only strip autoindent whitespace when the rest of the line is
all whitespace (glepnir).
fixes: vim/vim#19363closes: vim/vim#20290e3dedac77b
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: completion: cannot complete user cmd :K with 'ignorecase'
(rendcrx)
Solution: Skip the short-circuit when 'ignorecase' is set
(Yasuhiro Matsumoto)
The set_cmd_index() short-circuit for the :k command treats ":k<X>" as
":k {X}" (mark argument), which makes ":kz<Tab>" never reach the
command-name expansion path. With 'ignorecase' the same prefix on other
letters (":gz<Tab>") completes a user command like :Gz, so the result is
inconsistent. Skip the short-circuit when 'ignorecase' is set; default
behaviour is preserved so the existing :k tests still pass.
fixes: vim/vim#20241closes: vim/vim#20275b54e57ee54
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem: To goto or delete a bookmark, one needs to prefix a count
for the bookmark number (e.g., "2gb" to open bookmark#2).
As the bookmark list gets or deletes entries, the numbers
keep changing, requiring listing the bookmarks with qb to
discover the desired bookmark number. Typing gb or mB
without a count targets g:netrw_bookmarklist[-1].
Solution: If no count is given to gb or mB, list all bookmarks and
prompt for a number using inputlist(), similar to tag jump
with g].
closes: vim/vim#2021135b767a090
Co-authored-by: J. Paulo Seibt <jpseibt@gmail.com>
Problem: filetype: some html files are wrongly recognized as htmlangular
Solution: Use the \< atom to anchor ng-template and ng-content to start
of word (truffle)
Prevent false-positive htmlangular detection on words containing
'ng-template' or 'ng-content' as a substring (e.g. 'song-template',
'sing-content'). Anchor both branches with \< to require a word start,
matching the \<DTD\s\+XHTML\s idiom used five lines below.
related: neovim/neovim#39778.
closes: vim/vim#20246354ab1a69e
Co-authored-by: truffle <truffleagent@gmail.com>
Problem: User commands cannot handle single args with spaces
Solution: Add the -nargs=_ attribute (Maxim Kim)
-nargs=_ allow user commands to have a single argument with spaces.
For example given the following Test command and TestComplete function:
```
vim9script
def TestComplete(A: string, _: string, _: number): list<string>
var all = ["qqqq", "aaaa", "qq aa"]
return all->matchfuzzy(A)
enddef
command! -nargs=_ -complete=customlist,TestComplete Test echo <q-args>
```
`:Test q a<tab>` should successfully complete `qq aa`
fixes: vim/vim#20102closes: vim/vim#20189f0e874a129
Co-authored-by: Maxim Kim <habamax@gmail.com>
Problem: matchfuzzy() can crash on long multi-word patterns.
Solution: Clamp pat_chars to maxMatches and stop before calling
match_positions() when the buffer is full (glepnir).
closes: vim/vim#2020988b00d1c57
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: filetype: some Objective-C files are not recognized
Solution: Add g:filetype_mm override variable, improve the objective c
pattern detection (Keith Smiley).
closes: vim/vim#20221bc7f736a39
Co-authored-by: Keith Smiley <keithbsmiley@gmail.com>
Problem: out-of-bound read when recovering corrupted swap files
(Rahul Hoysala)
Solution: Validate the db_txt_start field when recovering a swap
file.
Supported by AI
de7a5b5425
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: runtime(netrw): command injection possible via crafted
directory names in NetrwMaps() (Christopher Lusk)
Solution: Temporarily remove B flag in NetrwMaps() to prevent command
injection
8e41c34aba
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: Pasting ". register without TextPut* autocommands breaks
subsequent TextPut* autocommands (after 9.2.0470).
Solution: Only decrement add_last_insert if it has been incremented
(zeertzjq).
closes: vim/vim#20192a70b7a85af
Problem: No way to hook into put commands
(yochem)
Solution: Introduce TextPutPre and TextPutPost autocommands
(Foxe Chen).
fixes: vim/vim#18701closes: vim/vim#20144e0781bd5bf
Co-authored-by: Foxe Chen <chen.foxe@gmail.com>
Problem: the bookmarks list can have duplicate entries, more often
in win32 (due to mixed slashes and capitalization) and when
g:netrw_keepdir=0 (which could introduce relative paths).
Duplicate entries could be: C:\foo\BAR\baz.file
c:\foo\bar\baz.file
c:/foo\BAR/baz.file
BAR/baz.file
Solution: Normalize the paths and make sure they are always absolute
(J. Paulo Seibt).
closes: vim/vim#2019474019bea8c
Co-authored-by: J. Paulo Seibt <jpseibt@gmail.com>
Problem: some functions can be run from the sandbox
Solution: Block them, so they are not accessible from a modeline
(q1uf3ng)
closes: vim/vim#19975fcc4276db3
Co-authored-by: q1uf3ng <q1uf3ng@protone.me>
Problem: runtime(netrw): bookmarking directory uses current dir
Solution: Correctly handle netrw actual directory (J. Paulo Seibt)
fixes: vim/vim#10481closes: vim/vim#20169ec76ac620b
Co-authored-by: J. Paulo Seibt <jpseibt@gmail.com>
Problem: The four pointer-resolution loops in u_read_undo() lack
an i != j guard, so a header whose uh_next.seq equals
its own uh_seq resolves uh_next.ptr to itself. On
buffer close, u_freeheader() sees uhp->uh_next.ptr !=
NULL and skips updating b_u_oldhead, so u_blockfree()
dereferences the freed header on the next iteration.
The same pattern applies to uh_prev, uh_alt_next and
uh_alt_prev. A crafted .un~ file in the same directory
as a text file can trigger the use-after-free and
subsequent double-free when the buffer is closed.
(Daniel Cervera)
Solution: Add an i != j guard to each of the four resolution
loops, matching the guard already present in the
duplicate-detection loop above.
closes: vim/vim#20168
Supported by AI
4f610f07b7
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: #39625 retained `matchparen.vim` as a shim that sources the new
`matchparen.lua` entrypoint, which is redundant since Lua runtime/plugin
files are sourced automatically and incurs startuptime cost solely for
the sake of not touching the tests.
Solution: Remove the shim and `source` the Lua plugin in directly in
tests.
Problem: Crash with invalid shellredir/shellpipe value
(bfredl)
Solution: Validate the option and allow only a single "%s".
fixes: vim/vim#20157closes: vim/vim#2015984ae09dd79
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: 'findfunc' only allows extra info for cmdline completion, not
for actually finding files (Maxim Kim, after 9.2.0451).
Solution: Handle returning a list of dicts when actually finding files.
Also fix crash on NULL string (zeertzjq).
fixes: vim/vim#20163closes: vim/vim#201649694ff58fe
Problem: No test that "abbr" in customlist completion is shown in pum.
Solution: Add some "abbr" fields to the existing test (zeertzjq).
closes: vim/vim#20165b207b5a2a3
Problem: 'findfunc' can't return extra info for cmdline completion
(Maxim Kim).
Solution: Handle 'findfunc' return value in cmdline completion like that
of "customlist" functions (zeertzjq).
fixes: vim/vim#20155closes: vim/vim#2015858124789aa
Problem: read_compound() in spellfile.c computes the size of the regex
pattern buffer using signed-int arithmetic on the attacker
controlled SN_COMPOUND sectionlen. With sectionlen=0x40000008
and UTF-8 encoding active the multiplication wraps to 27 while
the per-byte loop writes up to ~1B bytes, overflowing the heap.
Reachable when loading a crafted .spl file (e.g. via 'set spell'
after a modeline sets 'spelllang'). The cp/ap/crp allocations
have the same int + 1 overflow class (Daniel Cervera)
Solution: Use type size_t as buffer size and reject values larger than
COMPOUND_MAX_LEN (100000). Apply the same size_t treatment to
the cp/ap/crp allocations.
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-q4jv-r9gj-6cwv9299332917
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Problem: When find_start_brace() scans backwards for the enclosing
block, '{' and '}' inside // and /* */ comments are counted,
producing wrong indent for code following such comments
(rendcrx).
Solution: Implement FM_SKIPCOMM in findmatchlimit() to track block-
comment state and skip matches inside comments. Pass
FM_SKIPCOMM from cindent's call sites
(find_start_brace, find_match_char, cin_iswhileofdo,
get_c_indent).
fixes: vim/vim#4
fixes: vim/vim#648
fixes: vim/vim#19578closes: vim/vim#19581closes: vim/vim#20111c06002f3cb
Co-authored-by: magnus-rattlehead <magnus-rattlehead@users.noreply.github.com>
Problem: off-by-one bug in s:NetrwUnMarkFile()
Solution: Correctly loop through all buffers to unlet all variables
(J. Paulo Seibt)
When the function loops through buffers to clear s:netrwmarkfilelist_#
and s:netrwmarkfilemtch_#, it skips the last one at bufnr('$'), messing
up mark highlights and causing other functions that operate on those
arrays (like delete or rename) to target stale marked files.
The bufnr() help page says that bufnr("$") returns the highest buffer
number of existing buffers, so while ibuf < bufnr("$") does not clear
the last buffer-local arrays.
To reproduce:
Just opening a fresh Vim and running :Ex opens a netrw buffer at the
highest number. Then, typing mu after marking some files triggers the
mark highlight bug, and finally typing D would act like calling the
delete function against the previous marked files, as the buffer-local
arrays where not touched by s:NetrwUnMarkFile.
closes: vim/vim#201297ccc273a4c
Co-authored-by: J. Paulo Seibt <jpseibt@gmail.com>
Problem: When closing gvim with an unsaved unnamed buffer, choosing
"Yes" in the "Save changes?" dialog and then "Cancel" in the
file selection dialog either silently writes the buffer to a
file named "Untitled" (overwriting any existing file with
that name) or discards the buffer altogether
(vibs29, after v9.1.0265).
Solution: In dialog_changed(), if browse_save_fname() leaves the buffer
without a file name, treat it as a cancel and return without
saving. Also stop clearing the modified flag in the restore
path on write failure, so the unsaved changes are kept and
the caller (e.g. gui_shell_closed()) can also cancel the
close. Pre-fill the file dialog with "Untitled" to match
the preceding "Save changes to ..." prompt. Add a test for
the write-failure path (Hirohito Higashi).
fixes: vim/vim#20132closes: vim/vim#20143cf947e7ef0
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Problem: Cannot set 'path' option via modeline (zeertzjq, after v9.2.0435)
Solution: Revert the part that disallows setting 'path' via modeline.
closes: vim/vim#2013788fb739918
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: [security]: Backticks enclosed shell commands in the 'path'
option value are executed during completion (q1uf3ng).
Solution: Skip path entries containing backticks, add P_SECURE to 'path'
option, so that it cannot be set from a modeline (for symmetry with
the 'cdpath' option)
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-hwg5-3cxw-wvvg
Supported by AI.
190cb3c2b9
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: Completion with i_CTRL-X_CTRL-V doesn't use dict from cmdline
"customlist" completion.
Solution: Include abbr/kind/menu/info in the completion items
(zeertzjq).
closes: vim/vim#201392bfddbea47
Problem: Test_termdebug_tbreak(), Test_termdebug_basic(), and
Test_termdebug_toggle_break() use synchronous assert_equal()
to check breakpoint signs immediately after sending commands
to gdb. On slow CI (ASAN, ARM64, macOS) gdb may not have
processed the response yet, causing the sign to be missing.
Solution: Wrap the three assertions in WaitForAssert() to poll until
the signs are placed, matching the pattern already used by
the other assertions in the same tests (Jesse Rosenstock).
closes: vim/vim#2013320a124a6e0
Co-authored-by: Jesse Rosenstock <jmr@google.com>
Co-authored-by: Gemini
Problem: termdebug: Need a few more user commands
Solution: Add the :RunOrContinue and the :ToggleBreak user commands
(bennyyip)
closes: vim/vim#18283c975d62473
Co-authored-by: bennyyip <yebenmy@gmail.com>
Problem: Info popup isn't removed when selecting an item that doesn't
have "info" in cmdline completion, which is inconsistent with
Insert mode behavior.
Solution: Set pum_call_update_screen in cmdline mode (zeertzjq).
closes: vim/vim#201283bfffcc290
Nvim already behaves correctly. Add a screen test as there are none.
Problem: customlist completion cannot supply pum metadata
Solution: Allow each item returned by a customlist function to be
either a string or a Dict with keys "word", "abbr", "kind",
"menu" and "info" (Yasuhiro Matsumoto).
closes: vim/vim#201005c700152ae
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem: When an error line in a file passed to :cfile / :cgetfile is
longer than IOSIZE, qf_parse_file_pfx() copies the tail
into the fixed-size IObuff with STRMOVE(), overflowing the heap buffer.
The same code path can also loop indefinitely because
qf_parse_file_pfx() always returns QF_MULTISCAN when a
tail is present, and qf_init_ext() unconditionally goes
to "restofline" without bounding the tail length (Nabih).
Solution: Remove the STRMOVE() into IObuff. In the QF_MULTISCAN
branch, alias linebuf into the tail directly and update
linelen, requiring strict progress (new length less than
the previous length) before retrying; otherwise ignore
the line.
closes: vim/vim#20126
Supported by AI
77677c33de
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: tests: Test_shortmess_F3() is flaky on MS-Windows
Solution: Increase the sleep to 3s (Yasuhiro Matsumoto)
On MS-Windows time_differs() treats mtime as unchanged unless st_mtime
differs by more than 1 second, so a 2-second sleep can fall short when
the two writes straddle a second boundary. Bump the non-nanotime sleep
to 3 seconds.
closes: vim/vim#201172219c89013
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem: tests: flaky screendump Test_smoothscroll_incsearch()
Solution: Replace screendump test by WaitForAssert()
(Yasuhiro Matsumoto)
VerifyScreenDump fails consistently on the macos-15-intel CI runner.
Replace the dump comparisons with assertions that verify the actual
invariant under test: that the visible buffer view stays unchanged
across the four incremental-search keystrokes (i.e. skipcol is not
reset). Drop the now-unused dump files.
closes: vim/vim#20118e25933014c
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Problem:
The fallback that tokenizes `eap->arg` by unescaped whitespace (when the
parser doesn't pre-split via `EX_EXPAND` etc.) lives in `nlua_do_ucmd`,
so only user-command callbacks got `eap.fargs`. Builtin commands routed
through `nlua_call_excmd` have to re-parse the args themselves
(e.g. `M.ex_lsp`).
Solution:
- Move the tokenization into `nlua_push_eap` so every Lua handler sees
`eap.fargs`. Keep only the `EX_NOSPC` override in `nlua_do_ucmd` (the
`nargs=1`/`?` case which is genuinely user-command-specific).
- Drop the re-parse in `M.ex_lsp`.
Problem: With $d='[dir]', `:e $d/file.txt` opens the wrong file,
`:e $d/<Tab>` fails to complete, and `glob('$d/*')` returns
nothing. Wildcard characters inside expanded environment
variables get picked up by globbing again.
Solution: Turn the 4th parameter of expand_env_esc() from a bool into a
string of characters to escape in each expanded value. Callers
that pass the result to wildcard expansion should include
PATH_ESC_WILDCARDS in addition to " \t" (glepnir).
closes: vim/vim#2005320e98ff1cc
Problem: SPACE_IN_FILENAME is defined on most platforms but not on Unix.
As a result, set_context_for_wildcard_arg() on Unix always resets the
completion pattern at white space for Ex commands that take a
single file argument.
Solution: Drop the SPACE_IN_FILENAME ifdef (Maxim Kim)
fixes: vim/vim#18411closes: vim/vim#20090c2bda0add9
Co-authored-by: Maxim Kim <habamax@gmail.com>
Problem: Wrong behavior when executing register that ends in Insert
mode from Ctrl-O (Emilien Breton)
Solution: Use :startinsert etc. to restore Insert mode after executing
the register contents (zeertzjq).
fixes: vim/vim#20085closes: vim/vim#200916453a7c440
Problem: completion: no support for "noinsert" with 'wildmode' and
commandline completion
Solution: Add "noinsert" value to the 'wildmode' option, mirroring
'completeopt' "noinsert" behaviour (glepnir).
fixes: vim/vim#16551closes: vim/vim#20080af494af5ff
Problem: Cursor is not adjusted when 'cmdheight' is changed to cover
the cursor with 'splitkeep' ~= "cursor".
Solution: Handle window resize for 'splitkeep' after changing 'cmdheight'.
Ensure previous window height is set when changing 'splitkeep'
(Luuk van Baal).
closes: vim/vim#20043bd0f3e6da5
Co-authored-by: Luuk van Baal <luukvbaal@gmail.com>
Problem: A <Cmd> command in Insert mode can edit the current buffer,
e.g., with setline(). That edit appends to the current undo
block, but Insert mode does not know that the cursor line may
need to be saved again before the next typed edit. If the next
typed edit is a <BS> at the start of a line, it can join away
the line that was changed by the <Cmd> command before Insert
mode saves that updated line. The newest undo entry can then
still refer to the joined-away line, so undo sees a range past
the end of the buffer and fails with E438.
Solution: If a <Cmd> command in Insert mode changes the buffer, set
ins_need_undo so stop_arrow() refreshes Insstart. This lets
the next edit properly decide whether a new undo entry is
needed (Jaehwang Jung)
closes: vim/vim#20087
AI-assisted: Codex
e47daed442
Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>