mirror of
https://github.com/neovim/neovim.git
synced 2025-10-15 14:26:07 +00:00
fix(api): on_detach consistently before buf_freeall autocmds
Problem: on_detach may be called after buf_freeall and other important things, plus its textlock restrictions are insufficient. This can cause issues such as leaks, internal errors and crashes. Solution: disable buffer updates in buf_freeall, before autocommands (like the order after #35355 and when do_ecmd reloads a buffer). Don't do so in free_buffer_stuff; it's not safe to run user code there, and buf_freeall already runs before then; just free them to avoid leaks if buf_freeall autocommands registered more for some reason. Fixes #28084 Fixes #33967 Fixes #35116
This commit is contained in:
@@ -656,10 +656,6 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
|
||||
|
||||
buf->b_nwindows = nwindows;
|
||||
|
||||
// Disable buffer-updates for the current buffer.
|
||||
// No need to check `unload_buf`: in that case the function returned above.
|
||||
buf_updates_unload(buf, false);
|
||||
|
||||
buf_freeall(buf, ((del_buf ? BFA_DEL : 0)
|
||||
+ (wipe_buf ? BFA_WIPE : 0)
|
||||
+ (ignore_abort ? BFA_IGNORE_ABORT : 0)));
|
||||
@@ -788,6 +784,11 @@ void buf_freeall(buf_T *buf, int flags)
|
||||
bufref_T bufref;
|
||||
set_bufref(&bufref, buf);
|
||||
|
||||
buf_updates_unload(buf, false);
|
||||
if (!bufref_valid(&bufref)) {
|
||||
// on_detach callback deleted the buffer.
|
||||
return;
|
||||
}
|
||||
if ((buf->b_ml.ml_mfp != NULL)
|
||||
&& apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf)
|
||||
&& !bufref_valid(&bufref)) {
|
||||
@@ -935,7 +936,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
|
||||
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
|
||||
XFREE_CLEAR(buf->b_start_fenc);
|
||||
|
||||
buf_updates_unload(buf, false);
|
||||
buf_free_callbacks(buf);
|
||||
}
|
||||
|
||||
/// Go to another buffer. Handles the result of the ATTENTION dialog.
|
||||
|
@@ -2720,13 +2720,11 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
|
||||
goto theend;
|
||||
}
|
||||
u_unchanged(curbuf);
|
||||
buf_updates_unload(curbuf, false);
|
||||
buf_freeall(curbuf, BFA_KEEP_UNDO);
|
||||
|
||||
// Tell readfile() not to clear or reload undo info.
|
||||
readfile_flags = READ_KEEP_UNDO;
|
||||
} else {
|
||||
buf_updates_unload(curbuf, false);
|
||||
buf_freeall(curbuf, 0); // Free all things for buffer.
|
||||
}
|
||||
// If autocommands deleted the buffer we were going to re-edit, give
|
||||
|
Reference in New Issue
Block a user