Problem: home_replace() function can be improved
Solution: Refactor home_replace() to return the length of the string
(John Marriott).
In addition:
- in function set_b0_fname() move ulen into the block where it is used.
- In function findswapname() rework logic around displaying "swap file
already exists" dialogue so that literal message text is set once.
closes: vim/vim#20249a0931a90ee
Co-authored-by: John Marriott <basilisk@internode.on.net>
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>
CI currently uses clang-tidy 20, but this affects local builds
and CI is going to be upgraded sooner or later.
Some remaining systematic issues:
- clang-tidy warns agains any atoi() or atol() usage (because of no
error handling)
- functions which takes (char *fmt, char *only_string_arg) and expect
fmt to contain exactly one "%s" usage.
- error: initializing non-local variable with non-const expression depending on
uninitialized non-local variable (cppcoreguidelines-interfaces-global-init)
This is a much worse problem in C++ (hence C++ core guidelines) where
initialization is intermingled with arbitrary code execution. I
"think" in plain C, the linker will either resolve all these
deterministically or barf an error. But with some restructuring
we could make all static initialization actually static..
Problem:
followup to 55ceb314ca#39478
`:oldfiles` and swapfile `:recover` do not delegate to `vim.ui.select`.
Solution:
- Delegate to `vim.ui.select`.
- Fix a long-standing `recover_names` bug where `concat_fnames(dir_name,
files[i], true)` produced malformed `<dir>//<dir>/<file>` paths (also
fixes `swapfilelist()`).
Problem: No message kind and multiple events for :recover and
(non-prompt) swapfile attention messages.
Solution: Assign these the "list_cmd" and "wmsg" kind.
Problem:
On Windows, path separators may become inconsistent for various reasons,
which makes normalization quite painful.
Solution:
Normalize paths to `/` at the entry boundaries and always use it
internally, converting back only in rare cases where `\` is really
needed (e.g. cmd.exe/bat scripts?).
This is the first commit in a series of incremental steps.
Note:
* some funcs won't respect shellslash. e.g. `expand/fnamemodify`
* some funcs still respect shellslash, but will be updated in a follow
PR. e.g. `ex_pwd/f_chdir/f_getcwd`
* uv's built-in funcs always return `\`. e.g. `uv.cwd/uv.exepath`
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem: too many strlen() calls when adding strings to dicts
Solution: Refactor code to use string_T, use dict_add_string_len()
instead of dict_add_string() (John Marriott)
Additionally:
- In textprop.c, in function prop_fill_dict() use a string_T to store
local variable text_align.
- In popupwin.c, use a string_T to store struct member pp_name in struct
poppos_entry_T.
- In mark.c, refactor function add_mark() to pass in the length of
argument mname.
- In insexpand.c:
->Use a string_T to store the elements of static array
ctrl_x_mode_names.
->Refactor function trigger_complete_done_event():
->->change type of argument char_u *word to string_T *word.
->->make one access of array ctrl_x_mode_names instead of two.
->Refactor function ins_compl_mode() to accept a string_T to return the
resulting string.
- In fileio.c:
->Refactor function getftypewfd() to accept a string_T to return the
resulting string.
->In function create_readdirex_item() use a string_T to store local
variable q.
- In cmdexpand.c, store global cmdline_orig as a string_T.
- In autocmd.c, in function f_autocmd_get() use a string_T to store local
variables event_name and group_name. Measure their lengths once when
they are assigned so they are not remeasured on each call to
dict_add_string() in the subsequent for loop.
- In channel.c, in function channel_part_info() drop local variable status
and use s instead. Make s a string_T.
closes: vim/vim#19999c13232699d
Co-authored-by: John Marriott <basilisk@internode.on.net>
Problem: too many strlen() calls
Solution: refactor concat_fname() and remove calls to strlen()
(John Marriott)
Function `concat_fnames()` can make up to 5 calls to `STRLEN()` (either
directly or indirectly via `STRCAT()`). In many cases the lengths of
arguments `fname1` and/or `fname2` are either known or can simply be
calculated.
This Commit refactors this function to accept the lengths of arguments
`fname1` and `fname2` as arguments. It also adds new argument `ret` to
return the resulting string as a `string_T`.
Additionally:
- function `add_pack_dir_to_rtp()` in `scriptfile.c`:
Use a `string_T` to store local variables `new_rtp` and `afterdir`.
Replace calls to `STRCAT()` with calls to `STRCPY()`.
Change type of variable `keep` to `size_t` for consistency with
other lengths.
- function `qf_get_fnum()` in `quickfix.c`:
Use a `string_T` to store local variables `ptr` and `bufname`
- function `qf_push_dir()` in `quickfix.c`:
Use a `string_T` to store local variable `dirname`.
Replace call to `vim_strsave()` with `vim_strnsave()`.
- function `qf_guess_filepath()` in `quickfix.c`:
Use a `string_T` to store local variable `fullname`.
- function `make_percent_swname()` in `memline.c`:
Rename some variables to better reflect their use.
Use a `string_T` to store local variables `d` and `fixed_name`.
Slightly refactor to remove need to create an extra string.
- function `get_file_in_dir()` in `memline.c`:
Use a `string_T` to store local variables `tail` and `retval`.
Move some variables closer to where they are used.
- function `cs_resolve_file()` in `if_cscope.c`:
Use a `string_T` to store local variable `csdir`.
Remove one call to `STRLEN()`.
- function `add_pathsep()` in `filepath.c`:
Refactor and remove 1 call to `STRLEN()`
- function `set_init_xdg_rtp()` in `option.c`:
Use a `string_T` to store local variable `vimrc_xdg`.
closes: vim/vim#19854cb51add7ae
Co-authored-by: John Marriott <basilisk@internode.on.net>
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: using copy_option_part() can be improved
Solution: Refactor and use the return value of copy_option_part() to
avoid strlen() calls (John Marriott).
In addition, this commit includes the following changes:
memline.c:
- In recover_names():
- Replace calls to vim_strsave() with vim_strnsave() for the literal
strings
- Use a string_T to store local variable dir_name.
bufwrite.c:
- In buf_write()
- move variable wp to where it is used.
help.c:
- In fix_help_buffer():
- replace call to add_pathsep() with after_pathsep()
optionstr.c:
- In export_myvimdir():
- use a string_T to store local variable buf
- replace call to add_pathsep() with after_pathsep()
scriptfile.c:
- In do_in_path():
- use a string_T to store local variable buf
- measure the lengths of prefix and name once before the while loop
- replace call to add_pathsep() with after_pathsep()
- move some variables closer to where they are used
spellfile.c:
- In init_spellfile():
- use a string_T to store local variable buf
closes: vim/vim#19725a74e5fc5b9
Co-authored-by: John Marriott <basilisk@internode.on.net>
Problem: memline: a crafted swap files with bogus pe_page_count/pe_bnum
values could cause a multi-GB allocation via mf_get(), and
invalid pe_old_lnum/pe_line_count values could cause a SEGV
when passed to readfile() (ehdgks0627, un3xploitable)
Solution: Add bounds checks on pe_page_count and pe_bnum against
mf_blocknr_max before descending into the block tree, and
validate pe_old_lnum >= 1 and pe_line_count > 0 before calling
readfile().
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-r2gw-2x48-jj5p65c1a143c3
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: ml_append_int() crashes when appending lines near MAXCOL
length due to signed integer overflow in space_needed
calculation.
Solution: Change 'space_needed' from int to long to handle the
'len + INDEX_SIZE' computation without overflow. Update
db_free comparison casts from (int) to (long) to match.
Note: supported by AI claude
related: vim/vim#17935
related: vim/vim#18953
related: vim/vim#193320ece393844
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: ml_get_buf_len() does not consider text properties
(zeertzj)
Solution: Store text length excluding text properties length
in addition in the memline
related vim/vim#14123closes: vim/vim#14133a72d1be5a9
--------
Replace ml_line_len with ml_line_textlen to be explicit
that Nvim doesn't currently support Vim's text properties
and Nvim doesn't support lines with "ambiguous" length.
--------
vim-patch:9.1.0153: Text properties corrupted with fo+=aw and backspace
Problem: Text properties corrupted with fo+=aw and backspace
Solution: Allocate line and move text properties
(zeertzjq)
closes: vim/vim#141477ac1145fbe
vim-patch:9.1.0163: Calling STRLEN() to compute ml_line_textlen when not needed
Problem: Calling STRLEN() to compute ml_line_textlen when not needed.
Solution: Use 0 when STRLEN() will be required and call STRLEN() later.
(zeertzjq)
closes: vim/vim#1415582e079df81
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Group up to 15 vimpatch numbers in 1 line to guard against
'make formatc'.
1-liner for vim_versions, num_patches.
Automate '*Version' to remove version.h macros.
'-V1 -v' lists merged Vim versions.
Follow-up to #33721.
This doesn't seem to affect actual behavior for now, as these two lines
seem only reachable when the 'scrollback' option is changed, and options
can currently only be changed in the current buffer.
Problem: Text properties crossing lines not handled correctly.
Solution: When joining lines merge text properties if possible.
(Axel Forsman, closesvim/vim#5839, closesvim/vim#5683)
87be9be1db
Port docs from patch v8.1.0688.
Rewrite docs for ml_replace_buf_len().
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: When appending a line text property flags are not added.
Solution: Add text properties to a newly added line.
b56ac049ea
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: When deleting a line text property flags are not adjusted.
Solution: Adjust text property flags in preceding and following lines.
c1a9bc1a72
"textprop" feature remains N/A.
Porting to sync ml_delete_int() with Vim 8.2.0845 and later.
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: Cannot attach properties to text.
Solution: First part of adding text properties.
98aefe7c32
"textprop" feature remains N/A.
Porting for ml_replace_len().
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: ml_delete() often called with FALSE argument.
Solution: Use ml_delete_flags(x, ML_DEL_MESSAGE) when argument is TRUE.
ca70c07b72
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: line2byte() returns wrong value after adding textprop. (Yuto
Kimura)
Solution: Reduce the length by the size of the text property. (closesvim/vim#8759)
14c7530c4f
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: Text properties crossing lines not handled correctly.
Solution: When saving for undo include an extra line when needed and do not
adjust properties when undoing. (Axel Forsman, closesvim/vim#5875)
ML_DEL_UNDO, ML_APPEND_UNDO are no-opt because textprop feature is N/A.
a9d4b84d97
Co-authored-by: Bram Moolenaar <Bram@vim.org>
These are not needed after #35129 but making uncrustify still play nice
with them was a bit tricky.
Unfortunately `uncrustify --update-config-with-doc` breaks strings
with backslashes. This issue has been reported upstream,
and in the meanwhile auto-update on every single run has been disabled.
Problem: Byte2line() does not work correctly with text properties. (Billie
Cleek)
Solution: Take the bytes of the text properties into account.
(closesvim/vim#5334)
9df53b62de
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: Listener callback called at the wrong moment
Solution: Invoke listeners before calling ml_delete_int(). (closesvim/vim#4657)
acf7544cf6
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: Listener callback called for the wrong buffer.
Solution: Invoke listeners before calling ml_append_int().
250e3112c6
Co-authored-by: Bram Moolenaar <Bram@vim.org>
Problem: The swapfile attention message is not repeated after clearing
the screen.
After clearing the screen `msg_scrolled` is reset without
clearing other related variables, causing an assert.
Solution: Make the attention message part of the confirm prompt.
Call `msg_reset_scroll()`.
Problem: Computed previous buffer line count may be beyond end of
buffer. This results in signs being removed from `b_signcols`
that were never included in it, tripping an assertion.
Solution: Store the previous line count as it was before appending or
deleting lines. Use it to clamp the edited region when
clearing signs before a splice, after which it is reset.
Problem: Error thrown when for invalid line number which may be accessed
in an `on_detach` callback at which point line count is
intentionally set to 0.
Solution: Move empty memline check to before line number check.
Problem: [security]: heap-buffer-overflow with visual mode when
using :all, causing Vim trying to access beyond end-of-line
(gandalf)
Solution: Reset visual mode on :all, validate position in gchar_pos()
and charwise_block_prep()
This fixes CVE-2025-22134
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-5rgf-26wj-48v8c9a1e257f1
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: Prompts are emitted as messages events, where cmdline events
are more appropriate. The user input is also emitted as
message events in fast context, so cannot be displayed with
vim.ui_attach().
Solution: Prompt for user input through cmdline prompts.
Problem: Highlight group id is not propagated to the end of the message call
stack, where ext_messages are emitted.
Solution: Refactor message functions to pass along highlight group id
instead of attr id.
Problem:
- "process" is often used as a verb (`multiqueue_process_events`), which
is ambiguous for cases where it's used as a topic.
- The documented naming convention for processes is "proc".
- `:help dev-name-common`
- Shorter is better, when it doesn't harm readability or
discoverability.
Solution:
Rename "process" => "proc" in all C symbols and module names.
Problem:
Variables are often assigned multiple places in common patterns.
Solution:
Replace these common patterns with different patterns that reduce the
number of assignments.
Use `MAX` and `MIN`:
```c
if (x < y) {
x = y;
}
// -->
x = MAX(x, y);
```
```c
if (x > y) {
x = y;
}
// -->
x = MIN(x, y);
```
Use ternary:
```c
int a;
if (cond) {
a = b;
} els {
a = c;
}
// -->
int a = cond ? b : c;
```
Problem: Unnecessary STRLEN() in make_percent_swname()
Solution: Pass the end of "dir" to make_percent_swname()
(zeertzjq)
closes: vim/vim#15340242667ae14
Problem: Coverity reports dead code.
Solution: Remove the dead code. Also fix a mistake in ml_get_pos_len()
and update some comments (zeertzjq).
closes: vim/vim#141898c55d60658
Problem: More code can use ml_get_buf_len() instead of STRLEN().
Solution: Change more STRLEN() calls to ml_get_buf_len(). Also do not
set ml_line_textlen in ml_replace_len() if "has_props" is set,
because "len_arg" also includes the size of text properties in
that case. (zeertzjq)
closes: vim/vim#1418394b7c3233e