From 16d17c50bbccc0c3195656f09660babf45b5f803 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 19 May 2026 05:09:23 -0400 Subject: [PATCH] refactor: simplify aucmd_restbuf usage #39879 Problem: `aucmd_restbuf` must be guarded in case `aucmd_prepbuf` wasn't called. Solution: Update `aucmd_restbuf` to be a no-op if `aucmd_prepbuf` wasn't called. This requires `aco` to be zero-initialized. --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/options.c | 23 ++++++++--------------- src/nvim/autocmd.c | 21 ++++++++++++++++++--- src/nvim/buffer.c | 6 +++--- src/nvim/bufwrite.c | 4 ++-- src/nvim/diff.c | 2 +- src/nvim/edit.c | 4 ++-- src/nvim/eval/vars.c | 2 +- src/nvim/ex_cmds2.c | 2 +- src/nvim/ex_getln.c | 4 ++-- src/nvim/fileio.c | 2 +- src/nvim/lua/stdlib.c | 2 +- src/nvim/option.c | 4 ++-- src/nvim/quickfix.c | 6 +++--- src/nvim/terminal.c | 2 +- 15 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5ddddb1ad1..44604b205b 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -981,7 +981,7 @@ void nvim_buf_set_name(Buffer buf, String name, Error *err) } // Using aucmd_*: autocommands will be executed by rename_buffer - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, b); ren_ret = rename_buffer(name.data); aucmd_restbuf(&aco); @@ -1220,7 +1220,7 @@ Object nvim_buf_call(Buffer buf, LuaRef fn, lua_State *lstate, Error *err) } TRY_WRAP(err, { - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, b); Array args = ARRAY_DICT_INIT; diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c index 4443b08e7c..6778dbf12a 100644 --- a/src/nvim/api/options.c +++ b/src/nvim/api/options.c @@ -129,10 +129,9 @@ static int validate_option_value_args(Dict(option) *opts, char *name, bool allow } /// Create a dummy buffer and run the FileType autocmd on it. -static buf_T *do_ft_buf(const char *filetype, aco_save_T *aco, bool *aco_used, Error *err) - FUNC_ATTR_NONNULL_ARG(2, 3, 4) +static buf_T *do_ft_buf(const char *filetype, aco_save_T *aco, Error *err) + FUNC_ATTR_NONNULL_ARG(2, 3) { - *aco_used = false; if (filetype == NULL) { return NULL; } @@ -155,7 +154,6 @@ static buf_T *do_ft_buf(const char *filetype, aco_save_T *aco, bool *aco_used, E // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(aco, ftbuf); - *aco_used = true; set_option_direct(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, SID_NONE); set_option_direct(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, SID_NONE); @@ -241,15 +239,12 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) return (Object)OBJECT_INIT; } - aco_save_T aco; - bool aco_used; + aco_save_T aco = { 0 }; - buf_T *ftbuf = do_ft_buf(filetype, &aco, &aco_used, err); + buf_T *ftbuf = do_ft_buf(filetype, &aco, err); if (ERROR_SET(err)) { - if (aco_used) { - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - } + // Restore curwin/curbuf and a few other things. + aucmd_restbuf(&aco); if (ftbuf != NULL) { wipe_ft_buf(ftbuf); } @@ -263,11 +258,9 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) OptVal value = get_option_value_for(opt_idx, opt_flags, scope, from, err); + // Restore curwin/curbuf and a few other things. + aucmd_restbuf(&aco); if (ftbuf != NULL) { - if (aco_used) { - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - } wipe_ft_buf(ftbuf); } diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 328d17c232..f7d19c5a28 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1179,7 +1179,7 @@ int do_doautocmd(char *arg_start, bool do_msg, bool *did_something) void ex_doautoall(exarg_T *eap) { int retval = OK; - aco_save_T aco; + aco_save_T aco = { 0 }; char *arg = eap->arg; int call_do_modelines = check_nomodeline(&arg); bufref_T bufref; @@ -1357,9 +1357,24 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) /// Cleanup after executing autocommands for a (hidden) buffer. /// Restore the window as it was (if possible). /// +/// If `aco` was zero-initialized, then `aucmd_restbuf` may be safely called even if `aucmd_prepbuf` +/// was skipped: +/// +/// aco_save_T aco = { 0 }; +/// if (some_condition) { +/// aucmd_prepbuf(&aco, buf); +/// } +/// ... +/// aucmd_restbuf(&aco); // no-op if aucmd_prepbuf was skipped. +/// /// @param aco structure holding saved values void aucmd_restbuf(aco_save_T *aco) { + // NULL br_buf means `aucmd_prepbuf` was never called on this `aco`. + if (aco->new_curbuf.br_buf == NULL) { + return; + } + if (aco->use_aucmd_win_idx >= 0) { win_T *awp = aucmd_win[aco->use_aucmd_win_idx].auc_win; @@ -1534,7 +1549,7 @@ static void deferred_event(void **argv) } tv_dict_set_keys_readonly(v_event); - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, buf); apply_autocmds_group(event, fname, fname_io, false, group, buf, eap, data); aucmd_restbuf(&aco); @@ -1560,7 +1575,7 @@ static void deferred_optionset_modified(void **argv) bool new_val = (bool)(uintptr_t)argv[1]; OptVal old = BOOLEAN_OPTVAL(!new_val); OptVal new = BOOLEAN_OPTVAL(new_val); - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, buf); apply_optionset_autocmd_now(kOptModified, OPT_LOCAL, old, old, old, new, NULL); aucmd_restbuf(&aco); diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index b125bdc77f..5ef7cda17a 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -223,7 +223,7 @@ bool buf_ensure_loaded(buf_T *buf) return true; } - aco_save_T aco; + aco_save_T aco = { 0 }; // Make sure the buffer is in a window. aucmd_prepbuf(&aco, buf); @@ -421,7 +421,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) // The autocommands may have changed the current buffer. Apply the // modelines to the correct buffer, if it still exists and is loaded. if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL) { - aco_save_T aco; + aco_save_T aco = { 0 }; // Go to the buffer that was opened, make sure it is in a window. aucmd_prepbuf(&aco, old_curbuf.br_buf); @@ -4138,7 +4138,7 @@ bool buf_contents_changed(buf_T *buf) prep_exarg(&ea, buf); // Set curwin/curbuf to buf and save a few things. - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, newbuf); // We don't want to trigger autocommands now, they may have nasty diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index efc30b71a0..27bb77f82c 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -355,7 +355,7 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char linenr_T old_line_count = buf->b_ml.ml_line_count; int msg_save = msg_scroll; - aco_save_T aco; + aco_save_T aco = { 0 }; bool did_cmd = false; bool nofile_err = false; bool empty_memline = buf->b_ml.ml_mfp == NULL; @@ -518,7 +518,7 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char static void buf_write_do_post_autocmds(buf_T *buf, char *fname, exarg_T *eap, bool append, bool filtering, bool reset_changed, bool whole) { - aco_save_T aco; + aco_save_T aco = { 0 }; curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read diff --git a/src/nvim/diff.c b/src/nvim/diff.c index cc2715543c..c5fca1225c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -3795,7 +3795,7 @@ void ex_diffgetput(exarg_T *eap) } } - aco_save_T aco; + aco_save_T aco = { 0 }; if (eap->cmdidx != CMD_diffget) { // Need to make the other buffer the current buffer to be able to make diff --git a/src/nvim/edit.c b/src/nvim/edit.c index c320bbe64b..85fd450a10 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1424,7 +1424,7 @@ void ins_redraw(bool ready) if (ready && has_event(EVENT_TEXTCHANGEDI) && curbuf->b_last_changedtick_i != buf_get_changedtick(curbuf) && !pum_visible()) { - aco_save_T aco; + aco_save_T aco = { 0 }; varnumber_T tick = buf_get_changedtick(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them @@ -1444,7 +1444,7 @@ void ins_redraw(bool ready) if (ready && has_event(EVENT_TEXTCHANGEDP) && curbuf->b_last_changedtick_pum != buf_get_changedtick(curbuf) && pum_visible()) { - aco_save_T aco; + aco_save_T aco = { 0 }; varnumber_T tick = buf_get_changedtick(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index f8757d55e6..79712fa29e 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -3606,7 +3606,7 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (*varname == '&') { - aco_save_T aco; + aco_save_T aco = { 0 }; // Set curbuf to be our buf, temporarily. aucmd_prepbuf(&aco, buf); diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index cfd71a114e..1a36995b6e 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -689,7 +689,7 @@ void ex_listdo(exarg_T *eap) msg_listdo_overwrite--; if (save_ei != NULL) { buf_T *bnext; - aco_save_T aco; + aco_save_T aco = { 0 }; au_event_restore(save_ei); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 05ea2b3bb1..a9e7631223 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2493,7 +2493,7 @@ static buf_T *cmdpreview_open_buf(void) } // Rename preview buffer. - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, cmdpreview_buf); int retv = rename_buffer("[Preview]"); aucmd_restbuf(&aco); @@ -2687,7 +2687,7 @@ static void cmdpreview_restore_state(CpInfo *cpinfo) uhp != NULL; uhp = uhp->uh_next.ptr, ++count) {} - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, buf); // Ensure all the entries will be undone if (curbuf->b_u_synced == false) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 56e471981e..7b0d4c6d26 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3138,7 +3138,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) buf_T *savebuf; bufref_T bufref; int saved = OK; - aco_save_T aco; + aco_save_T aco = { 0 }; int flags = READ_NEW; // Set curwin/curbuf for "buf" and save some things. diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index c2e8394154..c4d98057ab 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -639,7 +639,7 @@ static int nlua_with(lua_State *L) Error err = ERROR_INIT; TRY_WRAP(&err, { - aco_save_T aco; + aco_save_T aco = { 0 }; win_execute_T win_execute_args; if (win) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 586bf0ddf9..b568ec2530 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4271,7 +4271,7 @@ OptVal get_option_value_for(OptIndex opt_idx, int opt_flags, const OptScope scop Error *err) { switchwin_T switchwin; - aco_save_T aco; + aco_save_T aco = { 0 }; tabpage_T *swtab = NULL; void *ctx = scope == kOptScopeWin ? (void *)&switchwin : scope == kOptScopeBuf ? (void *)&aco @@ -4322,7 +4322,7 @@ void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, cons } switchwin_T switchwin; - aco_save_T aco; + aco_save_T aco = { 0 }; tabpage_T *swtab = NULL; void *ctx = scope == kOptScopeWin ? (void *)&switchwin : scope == kOptScopeBuf ? (void *)&aco diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f1e2a08e96..93fce6050f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4199,7 +4199,7 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) // autocommands may cause trouble incr_quickfix_busy(); - aco_save_T aco; + aco_save_T aco = { 0 }; if (old_last == NULL) { // set curwin/curbuf to buf and save a few things @@ -5794,7 +5794,7 @@ static int vgr_process_files(win_T *wp, qf_info_T *qi, vgr_args_T *cmd_args, boo // need to be done now, in that buffer. And the modelines // need to be done (again). But not the window-local // options! - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, buf); apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, true, buf); do_modelines(OPT_NOWIN); @@ -5958,7 +5958,7 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin // Make sure this buffer isn't wiped out by autocommands. newbuf->b_locked++; // set curwin/curbuf to buf and save a few things - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, newbuf); // Need to set the filename for autocommands. diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 004a00265a..ac97de8edc 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -587,7 +587,7 @@ void terminal_open(Terminal **termpp, buf_T *buf) Terminal *term = *termpp; assert(term != NULL); - aco_save_T aco; + aco_save_T aco = { 0 }; aucmd_prepbuf(&aco, buf); if (term->sb_buffer != NULL) {