patch 8.0.0365: might free a dict item that wasn't allocated

Problem:    Might free a dict item that wasn't allocated.
Solution:   Call dictitem_free(). (Nikolai Pavlov)  Use this for
            b:changedtick.
diff --git a/src/buffer.c b/src/buffer.c
index b394d8e..73af50a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -832,7 +832,6 @@
     free_buffer_stuff(buf, TRUE);
 #ifdef FEAT_EVAL
     unref_var_dict(buf->b_vars);
-    buf->b_changedtick = &buf->b_ct_val;
 #endif
 #ifdef FEAT_LUA
     lua_buffer_free(buf);
@@ -874,31 +873,20 @@
 }
 
 /*
- * Initializes buf->b_changedtick.
+ * Initializes b:changedtick.
  */
     static void
 init_changedtick(buf_T *buf)
 {
-#ifdef FEAT_EVAL
-    dictitem_T *di = dictitem_alloc((char_u *)"changedtick");
+    dictitem_T *di = (dictitem_T *)&buf->b_ct_di;
 
-    if (di != NULL)
-    {
-	di->di_flags |= DI_FLAGS_FIX | DI_FLAGS_RO;
-	di->di_tv.v_type = VAR_NUMBER;
-	di->di_tv.v_lock = VAR_FIXED;
-	di->di_tv.vval.v_number = 0;
-	if (dict_add(buf->b_vars, di) == OK)
-	    buf->b_changedtick = &di->di_tv.vval.v_number;
-	else
-	{
-	    vim_free(di);
-	    buf->b_changedtick = &buf->b_ct_val;
-	}
-    }
-    else
-#endif
-	buf->b_changedtick = &buf->b_ct_val;
+    di->di_flags = DI_FLAGS_FIX | DI_FLAGS_RO;
+    di->di_tv.v_type = VAR_NUMBER;
+    di->di_tv.v_lock = VAR_FIXED;
+    di->di_tv.vval.v_number = 0;
+
+    STRCPY(buf->b_ct_di.di_key, "changedtick");
+    (void)dict_add(buf->b_vars, di);
 }
 
 /*
@@ -919,12 +907,12 @@
     }
 #ifdef FEAT_EVAL
     {
-	varnumber_T tick = *buf->b_changedtick;
+	varnumber_T tick = CHANGEDTICK(buf);
 
 	vars_clear(&buf->b_vars->dv_hashtab); /* free all buffer variables */
 	hash_init(&buf->b_vars->dv_hashtab);
 	init_changedtick(buf);
-	*buf->b_changedtick = tick;
+	CHANGEDTICK(buf) = tick;
     }
 #endif
 #ifdef FEAT_USR_CMDS
diff --git a/src/dict.c b/src/dict.c
index 07d1000..7074305 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -88,8 +88,7 @@
 	     * something recursive causing trouble. */
 	    di = HI2DI(hi);
 	    hash_remove(&d->dv_hashtab, hi);
-	    clear_tv(&di->di_tv);
-	    vim_free(di);
+	    dictitem_free(di);
 	    --todo;
 	}
     }
diff --git a/src/edit.c b/src/edit.c
index c4e7ddd..9a82432 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1668,7 +1668,7 @@
 #ifdef FEAT_AUTOCMD
     /* Trigger TextChangedI if b_changedtick differs. */
     if (ready && has_textchangedI()
-	    && last_changedtick != *curbuf->b_changedtick
+	    && last_changedtick != CHANGEDTICK(curbuf)
 # ifdef FEAT_INS_EXPAND
 	    && !pum_visible()
 # endif
@@ -1677,7 +1677,7 @@
 	if (last_changedtick_buf == curbuf)
 	    apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf);
 	last_changedtick_buf = curbuf;
-	last_changedtick = *curbuf->b_changedtick;
+	last_changedtick = CHANGEDTICK(curbuf);
     }
 #endif
 
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 1307d12..52527bc 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -2550,7 +2550,7 @@
     if (lnum < 0)	/* ignore type error in {lnum} arg */
 	lnum = 0;
     if (lnum != prev_lnum
-	    || changedtick != *curbuf->b_changedtick
+	    || changedtick != CHANGEDTICK(curbuf)
 	    || fnum != curbuf->b_fnum)
     {
 	/* New line, buffer, change: need to get the values. */
@@ -2572,7 +2572,7 @@
 	else
 	    hlID = (hlf_T)0;
 	prev_lnum = lnum;
-	changedtick = *curbuf->b_changedtick;
+	changedtick = CHANGEDTICK(curbuf);
 	fnum = curbuf->b_fnum;
     }
 
@@ -3957,7 +3957,7 @@
     dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
     dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
     dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
-    dict_add_nr_str(dict, "changedtick", *buf->b_changedtick, NULL);
+    dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
     dict_add_nr_str(dict, "hidden",
 		    buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
 		    NULL);
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 5ad094c..4c52cdf 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -660,7 +660,7 @@
 	need_wait_return = FALSE;
 	ex_pressedreturn = FALSE;
 	ex_no_reprint = FALSE;
-	changedtick = *curbuf->b_changedtick;
+	changedtick = CHANGEDTICK(curbuf);
 	prev_msg_row = msg_row;
 	prev_line = curwin->w_cursor.lnum;
 	if (improved)
@@ -673,7 +673,7 @@
 	lines_left = Rows - 1;
 
 	if ((prev_line != curwin->w_cursor.lnum
-		   || changedtick != *curbuf->b_changedtick) && !ex_no_reprint)
+		   || changedtick != CHANGEDTICK(curbuf)) && !ex_no_reprint)
 	{
 	    if (curbuf->b_ml.ml_flags & ML_EMPTY)
 		EMSG(_(e_emptybuf));
diff --git a/src/fileio.c b/src/fileio.c
index 73baecc..2001c0d 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4924,11 +4924,11 @@
     {
 	unchanged(buf, TRUE);
 #ifdef FEAT_AUTOCMD
-	/* buf->b_changedtick is always incremented in unchanged() but that
+	/* b:changedtick is always incremented in unchanged() but that
 	 * should not trigger a TextChanged event. */
-	if (last_changedtick + 1 == *buf->b_changedtick
+	if (last_changedtick + 1 == CHANGEDTICK(buf)
 					       && last_changedtick_buf == buf)
-	    last_changedtick = *buf->b_changedtick;
+	    last_changedtick = CHANGEDTICK(buf);
 #endif
 	u_unchanged(buf);
 	u_update_save_nr(buf);
diff --git a/src/main.c b/src/main.c
index ff173af..387221c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1162,15 +1162,15 @@
 #endif
 
 #ifdef FEAT_AUTOCMD
-	    /* Trigger TextChanged if b_changedtick differs. */
+	    /* Trigger TextChanged if b:changedtick differs. */
 	    if (!finish_op && has_textchanged()
-		    && last_changedtick != *curbuf->b_changedtick)
+		    && last_changedtick != CHANGEDTICK(curbuf))
 	    {
 		if (last_changedtick_buf == curbuf)
 		    apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL,
 							       FALSE, curbuf);
 		last_changedtick_buf = curbuf;
-		last_changedtick = *curbuf->b_changedtick;
+		last_changedtick = CHANGEDTICK(curbuf);
 	    }
 #endif
 
@@ -1388,11 +1388,11 @@
 		    /* Autocmd must have close the buffer already, skip. */
 		    continue;
 		buf = wp->w_buffer;
-		if (buf->b_ct_val != -1)
+		if (CHANGEDTICK(buf) != -1)
 		{
 		    apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname,
 						    buf->b_fname, FALSE, buf);
-		    buf->b_ct_val = -1;  /* note that we did it already */
+		    CHANGEDTICK(buf) = -1;  /* note that we did it already */
 		    /* start all over, autocommands may mess up the lists */
 		    next_tp = first_tabpage;
 		    break;
diff --git a/src/memline.c b/src/memline.c
index df799b1..01e8d5b 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -1649,7 +1649,7 @@
 	if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
 	{
 	    changed_int();
-	    ++*curbuf->b_changedtick;
+	    ++CHANGEDTICK(curbuf);
 	}
     }
     else
@@ -1663,7 +1663,7 @@
 	    if (i != 0)
 	    {
 		changed_int();
-		++*curbuf->b_changedtick;
+		++CHANGEDTICK(curbuf);
 		break;
 	    }
 	}
diff --git a/src/misc1.c b/src/misc1.c
index 9f86726..fbb1081 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -502,11 +502,11 @@
 
     /* used cached indent, unless pointer or 'tabstop' changed */
     if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
-				  || prev_tick != *wp->w_buffer->b_changedtick)
+				  || prev_tick != CHANGEDTICK(wp->w_buffer))
     {
 	prev_line = line;
 	prev_ts = wp->w_buffer->b_p_ts;
-	prev_tick = *wp->w_buffer->b_changedtick;
+	prev_tick = CHANGEDTICK(wp->w_buffer);
 	prev_indent = get_indent_str(line,
 				     (int)wp->w_buffer->b_p_ts, wp->w_p_list);
     }
@@ -2768,7 +2768,7 @@
 	}
 	changed_int();
     }
-    ++*curbuf->b_changedtick;
+    ++CHANGEDTICK(curbuf);
 }
 
 /*
@@ -3195,7 +3195,7 @@
 	need_maketitle = TRUE;	    /* set window title later */
 #endif
     }
-    ++*buf->b_changedtick;
+    ++CHANGEDTICK(buf);
 #ifdef FEAT_NETBEANS_INTG
     netbeans_unmodified(buf);
 #endif
diff --git a/src/structs.h b/src/structs.h
index 23ce826..1e1b1da 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1916,9 +1916,10 @@
 
     int		b_changed;	/* 'modified': Set to TRUE if something in the
 				   file has been changed and not written out. */
-    varnumber_T	*b_changedtick;	/* points into b:changedtick or b_ct_val;
+    dictitem16_T b_ct_di;	/* holds the b:changedtick value in
+				   b_ct_di.di_tv.vval.v_number;
 				   incremented for each change, also for undo */
-    varnumber_T b_ct_val;	/* fallback for b:changedtick */
+#define CHANGEDTICK(buf) ((buf)->b_ct_di.di_tv.vval.v_number)
 
     int		b_saving;	/* Set to TRUE if we are in the middle of
 				   saving the buffer. */
diff --git a/src/syntax.c b/src/syntax.c
index 6b90190..0d9cd2c 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -516,13 +516,13 @@
      */
     if (syn_block != wp->w_s
 	    || syn_buf != wp->w_buffer
-	    || changedtick != *syn_buf->b_changedtick)
+	    || changedtick != CHANGEDTICK(syn_buf))
     {
 	invalidate_current_state();
 	syn_buf = wp->w_buffer;
 	syn_block = wp->w_s;
     }
-    changedtick = *syn_buf->b_changedtick;
+    changedtick = CHANGEDTICK(syn_buf);
     syn_win = wp;
 
     /*
diff --git a/src/version.c b/src/version.c
index ffacb9a..d80a0ea 100644
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    365,
+/**/
     364,
 /**/
     363,