Problem: Currently `colnr_T` and `int` and the same type, so casting
`int *` to `colnr_T *` is redundant. Additionally, even if
they are changed to different types in the future, these casts
are incorrect as they won't work on big-endian platforms.
Solution: Remove the casts. Also fix two cases of passing false instead
of 0 to an integer argument (zeertzjq).
related: #19672
closes: #19907
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: 'showcmd' shows wrong Visual block size with 'linebreak' after
end char (after 7.4.467).
Solution: Exclude 'linebreak' from end position. Also fix confusing test
function names.
closes: #19908
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: if_lua: lua interface does not work with lua 5.5
(Lyderic Landry)
Solution: Use the new lua API `luaL_openselectedlibs()`
(Yee Cheng Chin)
Lua 5.5 removed the API function `openlibs` with `openselectedlibs`,
with `luaL_openlibs` replaced by a macro that just calls the new
`luaL_openselectedlibs` in the headers (see lua/lua@d738c8d18). This
broke Vim's dynamic Lua build as we try to redefine `luaL_openlibs`
ourselves and also this function can no longer be loaded from the lib.
Update the code to use the new API call instead to fix the issue.
fixes: #19814closes: #19842closes: #19909
Signed-off-by: Yee Cheng Chin <ychin.git@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: :packadd may lead to heap-buffer-overflow when all entries in
'runtimepath' have the same length (after 9.2.0291).
Solution: Check for comma after current entry properly (zeertzjq).
related: #19854
closes: #19911
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: E340 internal error when using method call on void value
(Peter Kenny)
Solution: Check for void value (Hirohito Higashi)
Using a method call on a void return value (e.g. "echo F()->empty()"
where F() returns void) caused an internal error E340. Now it properly
reports E1031 or E1186 depending on the context.
Changes:
- eval.c: check for void value before -> method call at runtime
- vim9expr.c: check for void type before -> method call at compile time
- vim9execute.c: check for void value in builtin function arguments and in
ISN_STORE
fixes: #19897closes: #19912
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
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: #19854
Co-authored-by: Christian Brabandt <cb@256bit.org>
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Amiga: no support for AmigaOS 3.x
Solution: Add support for building Vim on classic AmigaOS 3.x with the
bebbo cross-compiler and libnix (-noixemul) runtime
(Duncan Bowring).
The existing Make_ami.mak targets AmigaOS 4 (clib2), AROS, and MorphOS.
This patch adds a fourth target for classic 68k AmigaOS 3.x systems
(A1200, A4000, accelerated A500/A2000) using:
```
make -f Make_ami.mak UNM=AmigaOS3 BUILD=normal
```
Changes:
os_amiga.c:
- Add 256 KiB __stack cookie for OS3 (conservative for limited RAM)
- Add safe_Lock() wrapper to suppress "Please insert volume" system
requesters during path probing (benefits all Amiga targets)
- Suppress system requesters globally in mch_init() via pr_WindowPtr=-1
(Vim probes many paths at startup; Lock()/Open() on non-existent
volume names triggers blocking system requesters)
- Fix mch_get_host_name() for OS3 (libnix has no gethostname)
- Fix Delay() prototype for non-LATTICE compilers
- Fix nilfh file handle leak on error exit in mch_check_win()
os_amiga.h:
- Add fchown/fchmod/ftruncate no-op stubs for OS3/libnix
os_amiga_stubs.c (new):
- IM function stubs (referenced by optiondefs.h, no X11 on Amiga)
- mch_rmdir() via AmigaDOS DeleteFile()
- getpwuid()/getgrgid()/getuid() stubs (single-user system)
Make_ami.mak:
- Add AmigaOS3 target with -noixemul, -std=gnu99, -DWORDS_BIGENDIAN
blowfish.c:
- Accept WORDS_BIGENDIAN or AMIGA without requiring HAVE_CONFIG_H
xdiff/xmacros.h:
- Make SIZE_MAX fallback unconditional (not just hpux/VMS)
All OS3-specific changes are guarded by:
#if defined(__GNUC__) && defined(AMIGA) && !defined(__amigaos4__)
Tested on FS-UAE with Workbench 3.1: 23 automated tests passing.
Binary size: 2.2 MiB with -Os -m68020 -DFEAT_NORMAL.
This is the first modern Vim build for classic 68k AmigaOS since
Vim 5.8 circa 1998. Vim was originally released on the Amiga
(Fred Fish Disk 591, 1991).
closes: #19840
Signed-off-by: Duncan Bowring <duncan@bowring.us>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: 'linebreak' may lead to wrong Visual block highlighting when
end char occupies multiple cells (after 7.4.467).
Solution: Exclude 'linebreak' from the ending column instead of setting
'virtualedit' temporarily (zeertzjq).
fixes: #19898closes: #19900
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Accumulating CSI argument digits without an upper bound causes
signed integer overflow when the argument exceeds LONG_MAX.
Solution: Clamp CSI argument accumulation to CSI_ARG_MISSING to prevent
signed integer overflow (Yasuhiro Matsumoto).
closes: #19894
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: filetype: not all ObjectScript routines are recognized
Solution: Also detect "%RO" and "iris" patterns inside *.rtn files
(Hannah Kimura)
closes: #19873
Signed-off-by: Hannah Kimura <hannah.kimura@intersystems.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: still some unnecessary (int) casts in alloc()
Solution: Remove more unnecessary (int) casts before alloc() calls
(Yasuhiro Matsumoto).
Follow-up to patch 9.2.0283. Remove remaining (int) casts in
vim9script.c and netbeans.c.
vim9script.c: lengths are derived from STRLEN() on file paths,
bounded by PATH_MAX. netbeans.c: all operands are already int,
so the (int) cast is redundant and no truncation can occur.
related: #19888
closes: #19893
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: :syn sync grouphere may go beyond end of line.
Solution: Start searching for the end of region at the end of match
instead of a possibly invalid position (zeertzjq).
closes: #19896
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When a tabpanel expression returns a different number of lines on
successive evaluations, the computed row offset can become negative,
causing screen_fill() to receive an invalid start_row and crash
(after v9.1.1391).
Solution: Clamp the row argument in screen_fill_tailing_area() to zero,
add a safety check in screen_fill() for negative start_row
(Michał Majchrowicz)
Supported by AI
Co-authored-by: Michał Majchrowicz <mmajchrowicz@afine.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: unnecessary (int) casts before alloc() calls, can cause
truncation and heap overflows (sgInnora)
Solution: Remove casts (Yasuhiro Matsumoto)
alloc() already accepts size_t, so (int) casts on size_t values are
redundant and could theoretically cause truncation on values > INT_MAX.
Remove the casts and change alloc_cmdbuff() signature from int to
size_t to match.
Note: list_alloc_with_items() keeps its int parameter since lv_len and
lv_with_items are int, and the call site already has an INT_MAX guard.
fixes: #19888closes: #19889
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tests: Test_viminfo_len_overflow() fails
Solution: Catch E342 (Yasuhiro Matsumoto).
Test_viminfo_len_overflow tries to allocate ~4GB, which may throw E342
(out of memory) depending on the platform's memory allocation behavior.
This is an acceptable outcome since the test's purpose is to verify
that Vim does not crash on a crafted viminfo entry.
closes: #19891
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tests: Test_netrw_FileUrlEdit.. fails on Windows
(after 3e60f03d94)
Solution: Skip the test on Windows (Yasuhiro Matsumoto).
The Test_netrw_FileUrlEdit_pipe_injection() test fails on Windows with
E303 because '|' is not a valid filename character on Windows. Since
the pipe character cannot appear in a Windows filename, the command
injection vector this test guards against does not apply on Windows.
closes: #19890
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: libvterm CSI parser does not bounds-check argi against
CSI_ARGS_MAX, allowing excess ';'-separated arguments to
write past the end of the args array (sentinel404).
Solution: Drop excess arguments.
Supported by AI
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Reading a crafted viminfo file can cause a heap buffer
overflow because the length value from getdigits() is cast to
int, truncating large size_t values
Solution: Remove the (int) cast when calling alloc() (sentinel404)
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: BSU/ESU are output directly to the terminal
Solution: Route them through out_buf() and flush the output directly,
increase the OUT_SIZE terminal buffer (Yasuhiro Matsumoto)
Route synchronized-output control sequences through out_buf and flush
explicitly at protocol boundaries, instead of forcing BSU/ESU through
ui_write() directly.
Also increase the terminal output buffer from 2047 to 8191 bytes so
large redraws are emitted in fewer writes.
The important guarantee here is terminal-visible ordering: BSU must
reach the terminal before the batched redraw bytes, ESU must reach the
terminal after them, and FLUSH must emit ESU and BSU together, then
flush immediately.
Benchmark: PTY redraw workload with TERM=xterm-256color, long wrapped
lines, cursorline, listchars, horizontal scrolling, and repeated redraw!.
write syscalls: 8514 -> 5094 (-40.2%)
wall time: 0.568s -> 0.495s (-12.9%) on valid runs in this environment
closes: #19862
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel: undefined behaviour with large tabpanelop columns
(Michał Majchrowicz)
Solution: Error out for too large column values
Co-authored-by: Michał Majchrowicz <mmajchrowicz@afine.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: test: trailing spaces used in tests
Solution: Rewrite tests to avoid trailing spaces (Paul Ollis).
Some tests currently rely on trailing whitespace at the end of lines,
escaped with '\'. I have demonstrated in another PR, such spaces can be
inadvertently removed and this is difficult to spot.
Note: there are more trailing spaces in a few more test files, see
testdir/test_codestyle.vim. Those are not yet removed.
closes: #19838
Signed-off-by: Paul Ollis <paul@cleversheep.org>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: configure: Link error on Solaris
(idgn23, after v9.2.0153)
Solution: Move the check for the nsl library a bit earlier,
regenerate configure
fixes: #19803
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: memory leak in call_oc_method()
Solution: Clean up argvars in the failure case
(Huihui Huang)
closes: #19828
Signed-off-by: Huihui Huang <625173@qq.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: typeahead buffer overflow during mouse drag event
Solution: Change the guard from 5 to 10 to account for the worst case
(Yasuhiro Matsumoto).
The typeahead buffer guard in mch_inchar() only reserved 5 bytes per
iteration, but a mouse event writes up to 7 bytes (3 header + 4
coordinates) and a scroll event with modifiers writes up to 10 bytes
(3 modifier + 3 scroll + 4 coordinates). During fast mouse dragging,
3+ events could queue up and overflow the 20-byte buffer, corrupting
adjacent static variables and causing garbage bytes (including Ctrl-Z)
to be fed into the input stream, which triggered nv_suspend/ex_stop.
closes: #19851
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: unnecessary restrictions for defining dictionary function
names
Solution: Allow defining dict function with bracket key that is not a
valid identifier (thinca)
In Vim script, "function obj.func()" and "function obj['func']()" both
define a dictionary function. However, the bracket form required the
key to match function naming rules (eval_isnamec), so
"function obj['foo-bar']()" failed with E475.
Assigning and calling already work: "let obj['foo-bar'] = obj.func"
and "call obj['foo-bar']()" are valid. Only the definition was
incorrectly restricted.
Skip the identifier check when the name comes from fd_newkey (i.e. the
key was given in bracket notation). Dictionary keys may be any string.
Supported by AI
closes: #19833
Signed-off-by: thinca <thinca@gmail.com>
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot disable kitty keyboard protocol in vim :terminal
Solution: Handle "CSI <u" sequence in libvterm (Julio B).
related: v9.0.0930
closes: #19837
Signed-off-by: Julio B <julio.bacel@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: hlset() cannot handle attributes with spaces
Solution: Handle attributes with spaces by quoting those
(Yasuhiro Matsumoto).
hlset(hlget('Normal')) fails with E416 when a highlight attribute value
contains spaces (e.g. font name "Monospace 10"). hlg_add_or_update()
builds a string like "font=Monospace 10" and passes it to do_highlight(),
whose parser splits on whitespace and treats "10" as a separate key
without "=".
Fix by quoting values with single quotes (e.g. font='Monospace 10')
when the value contains spaces and the attribute is a key=value pair.
do_highlight() already supports single-quoted values.
closes: #19843
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: invalid lnum when pasting text copied blockwise
(KillTheMule)
Solution: Subtract nr_lines from curwin->w_cursor.lnum when calling
changed_lines() in do_put() (Pierluigi Lenoci)
When doing a blockwise paste beyond the end of the buffer, new lines are
appended and nr_lines is incremented accordingly. However, the
changed_lines() call used curwin->w_cursor.lnum as the "lnume" argument
(the first line below the changed lines BEFORE the change), which is
incorrect because the cursor has already been moved past the newly
appended lines.
Fix by subtracting nr_lines from curwin->w_cursor.lnum, so that lnume
correctly reflects the state before the change, as documented in
changed_lines().
Add a listener test to verify the correct values are reported.
Port of neovim/neovim#12733.
fixes: #6660closes: #19844
Signed-off-by: Pierluigi Lenoci <pierluigi.lenoci@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: terminal: redraws are slow (Mao-Yining)
Solution: Disable redrawing in handle_movecursor()
(Yasuhiro Matsumoto)
handle_movecursor callback was calling update_cursor() with redraw=TRUE
on every cursor move inside vterm_input_write(). This triggered
gui_mch_flush() (GdiFlush + DWriteContext_Flush) and TextChangedT
autocmd for each cursor move. ConPTY output contains ~17 cursor moves
per 4KB chunk, each flush taking ~5ms, resulting in 80-110ms per chunk.
Fix by passing FALSE to update_cursor() in handle_movecursor since
write_to_term() already calls update_cursor() with proper redraw after
vterm_input_write() finishes.
Also set vterm_screen_set_damage_merge() to VTERM_DAMAGE_SCROLL so that
damage callbacks are buffered until vterm_screen_flush_damage() instead
of being emitted per cell.
fixes: #19845closes: #19846
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When a popup window overlapping a status line is closed or
hidden, the status line is not redrawn, leaving ghost
artifacts from the popup.
Solution: popup_free() and popup_hide() call
redraw_all_later(UPD_NOT_VALID) which marks window contents
for redraw but does not set w_redr_status. The diff-based path
in may_update_popup_mask() that normally sets w_redr_status
is skipped when redrawing_all_win is TRUE. Add status_redraw_all
calls to ensure status lines are properly redrawn
(Yasuhiro Matsumoto).
closes: #19830
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel: corrupted tabpanel during scrolling causing flicker
Solution: When the tabpanel is visible, force a line-by-line redraw in
win_do_lines() similarly to popup handling (Yasuhiro Matsumoto).
When a vertical tabpanel is visible, terminal scroll operations in
win_do_lines() affect the full screen width, corrupting the tabpanel
area. The tabpanel is then redrawn via redraw_tabpanel, causing visible
flicker. Return FAIL to force line-by-line redraw instead, analogous to
the existing popup_visible check.
closes: #19832
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: memory leak in add_mark()
Solution: Free lpos in the error case when it hasn't been added to the
dict yet (Huihui Huang)
closes: #19827
Signed-off-by: Huihui Huang <625173@qq.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Unnecessary memory allocation in set_callback(); after
set_callback(), callers must manually free the source
callback's name if cb_free_name is set.
Solution: Refactor set_callback() to re-use the callback name when
possible to avoid extra memory allocations and clean up so the
callers do not have to take care themselves (Shane Harper).
closes: #19831
Signed-off-by: Shane Harper <shane@shaneharper.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: The visual selection size is not displayed in the showcmd area
when entering visual mode from a script or mapping, because
char_avail() incorrectly reports input as pending. This causes
test failure on CI with the ASAN CI runner.
Solution: Replace char_avail() with explicit checks for an empty stuff
buffer, empty typeahead buffer, and not running a script
(zeertzjq).
related: #19801
closes: #19824
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tests: Test_popup_opacity_vsplit() fails in a wide terminal
(after v9.2.0230)
Solution: Reduce terminal window size to 60, force termguicolors to make
the opacity visible; enable termguicolors so that the opacity
is visually apparent in the screen dump.
related: #19824
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: w_locked can be bypassed when recursively set if not restored
to its prior value.
Solution: Rather than save/restore everywhere, just make it a count,
like other locks (Sean Dewar)
Requires the previous commit, otherwise b_nwindows will be wrong in
tests, which causes a bunch of weird failures.
closes: #19728
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: close_buffer() callers incorrectly handle b_nwindows,
especially after nasty autocmds, allowing it to go
out-of-sync. May lead to buffers that can't be unloaded, or
buffers that are prematurely freed whilst displayed.
Solution: Modify close_buffer() and review its callers; let them
decrement b_nwindows if it didn't unload the buffer. Remove
some now unneeded workarounds like 8.2.2354, 9.1.0143,
9.1.0764, which didn't always work (Sean Dewar)
close_buffer() now doesn't decrement b_nwindows when not unloading buf, or when
buf isn't w_buffer after autocmds (they would've already decremented it).
Callers are now expected to decrement b_nwindows if w_buffer is not NULL after
close_buffer(), and when still intending to switch buffers or close win, for two
reasons:
- close_buffer() autocmds may have switched buffers. The new w_buffer's
b_nwindows would also need decrementing.
- After close_buffer(), callers may opt to not switch w_buffer or close win.
b_nwindows would need to be incremented again. (unless w_buffer is NULL from
being unloaded; callers are already forced to find a new buffer then)
These were the main causes of b_nwindows bugs, as these cases could not be
reliably detected, and went largely unhandled.
NOTE: if close_buffer() autocmds switch buffers, close_buffer() is not called
for that new buffer before decrementing b_nwindows. This may skip side-effects
like from 'bufhidden', but I think it's mostly harmless, and was already
happening in other places.
Let's see how this goes... Other details: (I have lots to say!)
It's OK to pass a win to close_buffer() that isn't showing buf (used by
set_curbuf()). In that case, we skip some side-effects and don't decrement
b_nwindows, but may still unload buf if hidden.
buf_freeall() now returns whether it freed anything. Removes some repeated
checks in close_buffer().
Preserve close_buffer()'s behaviour when called by win_free_popup() after its
popup was already removed from the window list. This made win_valid_any_tab()
return FALSE, so we skip things that originally checked it in that case.
Add "set_context" to close_buffer() to preserve do_ecmd()'s behaviour of only
setting b_last_cursor and/or calling buflist_setfpos() when not splitting
(see 7.2.041: https://groups.google.com/g/vim_dev/c/ZGgNvaylNzI/m/WHxjhnuxqB0J)
Without this, Test_marks_cmd() fails from its ' mark differing. Don't use
oldwin though; it's not always the window with the closed buf, especially
after BufLeave autocmds in do_ecmd(). Also, only set context if win is really
displaying buf.
Don't bail in do_ecmd() if buf was deleted but curwin->w_buffer is NULL; that
leaves curwin open to a NULL buffer! Use lastbuf instead, like set_curbuf().
I don't think it's possible for buf to be deleted by close_buffer() anyway, as
b_locked was set (which I can't see a way to bypass, unlike b_locked_split).
Maybe such checks can be removed, but I'd rather not risk that here.
Don't set curwin to previouswin in set_curbuf(); shouldn't be needed, otherwise
may lead to curbuf != curwin->w_buffer if autocmds switch to a window showing
buf, as that skips enter_buffer()? Was introduced back in 7.3.557 to avoid
cases where autocmds switch windows, possibly leaving previouswin with a NULL
buffer. Since 7.4.2312 and 7.4.2328, close_buffer() and buf_freeall() already
handles this. I've added an assert() as a sanity check anyway.
In free_all_mem(), set b_nwindows to 0 before close_buffer() so buffers can be
wiped if still in a window before win_free_all(). Needed as close_buffer() now
skips unloading buffers that aren't hidden if win is NULL. If it's possible for
free_all_mem()'s :tabonly! and :only! to not close all windows before freeing,
then this issue was also previously possible if b_nwindows > 1.
related: #19728
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: if close_buffer() in set_curbuf() unloads curbuf, NULL pointer
accesses may occur from enter_buffer() calling
end_visual_mode(), as curbuf is already abandoned and possibly
unloaded. Also, selection registers may not contain the
selection with clipboard+=autoselect(plus).
Solution: Move close_buffer()'s end_visual_mode() call to buf_freeall(), after
any autocmds that may restart it, but just before freeing anything
(Sean Dewar)
related: #19728
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>