aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2019-08-23 10:31:35 +0200
committerGitHub <noreply@github.com>2019-08-23 10:31:35 +0200
commit79ea7709b7cab13b89d98088f4733a354a7f2a54 (patch)
tree2c5c0bb0f9e44e96c5d8fce7d2772af8d8041bbe
parentc6eb1f42bec06e92c2c5ee9a523af4e46ac05083 (diff)
parent71378a40308cd987626ebccb5882897d41c86c7a (diff)
downloadrneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.tar.gz
rneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.tar.bz2
rneovim-79ea7709b7cab13b89d98088f4733a354a7f2a54.zip
Merge #9163 'fix crash wiping buffer after getbufinfo()'
-rw-r--r--src/nvim/buffer.c41
-rw-r--r--src/nvim/buffer_defs.h4
-rw-r--r--src/nvim/eval/typval.c2
-rw-r--r--src/nvim/testdir/test_autocmd.vim1
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',