diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2019-08-23 10:31:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-23 10:31:35 +0200 |
commit | 79ea7709b7cab13b89d98088f4733a354a7f2a54 (patch) | |
tree | 2c5c0bb0f9e44e96c5d8fce7d2772af8d8041bbe | |
parent | c6eb1f42bec06e92c2c5ee9a523af4e46ac05083 (diff) | |
parent | 71378a40308cd987626ebccb5882897d41c86c7a (diff) | |
download | rneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.tar.gz rneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.tar.bz2 rneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.zip |
Merge #9163 'fix crash wiping buffer after getbufinfo()'
-rw-r--r-- | src/nvim/buffer.c | 41 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 1 |
4 files changed, 28 insertions, 20 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index a545112360..3ccbb4efdd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -97,6 +97,11 @@ static char *e_auabort = N_("E855: Autocommands caused command to abort"); // Number of times free_buffer() was called. static int buf_free_count = 0; +typedef enum { + kBffClearWinInfo = 1, + kBffInitChangedtick = 2, +} BufFreeFlags; + // Read data from buffer for retrying. static int read_buffer( @@ -619,9 +624,9 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) free_buffer(buf); } else { if (del_buf) { - /* Free all internal variables and reset option values, to make - * ":bdel" compatible with Vim 5.7. */ - free_buffer_stuff(buf, true); + // Free all internal variables and reset option values, to make + // ":bdel" compatible with Vim 5.7. + free_buffer_stuff(buf, kBffClearWinInfo | kBffInitChangedtick); // Make it look like a new buffer. buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; @@ -756,7 +761,12 @@ static void free_buffer(buf_T *buf) { handle_unregister_buffer(buf); buf_free_count++; - free_buffer_stuff(buf, true); + // b:changedtick uses an item in buf_T. + free_buffer_stuff(buf, kBffClearWinInfo); + if (buf->b_vars->dv_refcount > DO_NOT_FREE_CNT) { + tv_dict_add(buf->b_vars, + tv_dict_item_copy((dictitem_T *)(&buf->changedtick_di))); + } unref_var_dict(buf->b_vars); aubuflocal_remove(buf); tv_dict_unref(buf->additional_data); @@ -781,22 +791,19 @@ static void free_buffer(buf_T *buf) } } -/* - * Free stuff in the buffer for ":bdel" and when wiping out the buffer. - */ -static void -free_buffer_stuff( - buf_T *buf, - int free_options // free options as well -) +/// Free stuff in the buffer for ":bdel" and when wiping out the buffer. +/// +/// @param buf Buffer pointer +/// @param free_flags BufFreeFlags +static void free_buffer_stuff(buf_T *buf, int free_flags) { - if (free_options) { + if (free_flags & kBffClearWinInfo) { clear_wininfo(buf); // including window-local options free_buf_options(buf, true); ga_clear(&buf->b_s.b_langp); } { - // Avoid loosing b:changedtick when deleting buffer: clearing variables + // Avoid losing b:changedtick when deleting buffer: clearing variables // implies using clear_tv() on b:changedtick and that sets changedtick to // zero. hashitem_T *const changedtick_hi = hash_find( @@ -806,7 +813,9 @@ free_buffer_stuff( } vars_clear(&buf->b_vars->dv_hashtab); // free all internal variables hash_init(&buf->b_vars->dv_hashtab); - buf_init_changedtick(buf); + if (free_flags & kBffInitChangedtick) { + buf_init_changedtick(buf); + } uc_clear(&buf->b_ucmds); // clear local user commands buf_delete_signs(buf, (char_u *)"*"); // delete any signs bufhl_clear_all(buf); // delete any highligts @@ -1785,7 +1794,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) if (aborting()) { // autocmds may abort script processing return NULL; } - free_buffer_stuff(buf, false); // delete local variables et al. + free_buffer_stuff(buf, kBffInitChangedtick); // delete local vars et al. // Init the options. buf->b_p_initialized = false; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index b11eaefdd0..5e700940b0 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -508,9 +508,9 @@ struct file_buffer { int b_changed; // 'modified': Set to true if something in the // file has been changed and not written out. - /// Change identifier incremented for each change, including undo + /// Change-identifier incremented for each change, including undo. /// - /// This is a dictionary item used to store in b:changedtick. + /// This is a dictionary item used to store b:changedtick. ChangedtickDictItem changedtick_di; varnumber_T b_last_changedtick; // b:changedtick when TextChanged or diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 91a1d083c7..106b8f6eed 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1272,7 +1272,7 @@ void tv_dict_item_free(dictitem_T *const item) /// @param[in] di Item to copy. /// /// @return [allocated] new dictionary item. -static dictitem_T *tv_dict_item_copy(dictitem_T *const di) +dictitem_T *tv_dict_item_copy(dictitem_T *const di) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key); diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index b686d0292f..4c9df0cb16 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -811,7 +811,6 @@ endfunc " Test for autocommand that deletes the current buffer on BufLeave event. " Also test deleting the last buffer, should give a new, empty buffer. func Test_BufLeave_Wipe() - throw 'skipped: TODO: ' %bwipe! let content = ['start of test file Xxx', \ 'this is a test', |