changeset 4287:dc3efb6d5a08 v7.3.893

updated for version 7.3.893 Problem: Crash when using b:, w: or t: after closing the buffer, window or tabpage. Solution: Allocate the dictionary instead of having it part of the buffer/window/tabpage struct. (Yukihiro Nakadaira)
author Bram Moolenaar <bram@vim.org>
date Mon, 15 Apr 2013 12:27:36 +0200
parents afcc61d24129
children 4748965c1981
files src/buffer.c src/eval.c src/fileio.c src/proto/eval.pro src/structs.h src/version.c src/window.c
diffstat 7 files changed, 140 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -648,6 +648,9 @@ free_buffer(buf)
     buf_T	*buf;
 {
     free_buffer_stuff(buf, TRUE);
+#ifdef FEAT_EVAL
+    unref_var_dict(buf->b_vars);
+#endif
 #ifdef FEAT_LUA
     lua_buffer_free(buf);
 #endif
@@ -689,8 +692,8 @@ free_buffer_stuff(buf, free_options)
 #endif
     }
 #ifdef FEAT_EVAL
-    vars_clear(&buf->b_vars.dv_hashtab); /* free all internal variables */
-    hash_init(&buf->b_vars.dv_hashtab);
+    vars_clear(&buf->b_vars->dv_hashtab); /* free all internal variables */
+    hash_init(&buf->b_vars->dv_hashtab);
 #endif
 #ifdef FEAT_USR_CMDS
     uc_clear(&buf->b_ucmds);		/* clear local user commands */
@@ -1694,6 +1697,17 @@ buflist_new(ffname, sfname, lnum, flags)
 	    vim_free(ffname);
 	    return NULL;
 	}
+#ifdef FEAT_EVAL
+	/* init b: variables */
+	buf->b_vars = dict_alloc();
+	if (buf->b_vars == NULL)
+	{
+	    vim_free(ffname);
+	    vim_free(buf);
+	    return NULL;
+	}
+	init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
+#endif
     }
 
     if (ffname != NULL)
@@ -1778,10 +1792,6 @@ buflist_new(ffname, sfname, lnum, flags)
     buf->b_wininfo->wi_fpos.lnum = lnum;
     buf->b_wininfo->wi_win = curwin;
 
-#ifdef FEAT_EVAL
-    /* init b: variables */
-    init_var_dict(&buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
-#endif
 #ifdef FEAT_SYN_HL
     hash_init(&buf->b_s.b_keywtab);
     hash_init(&buf->b_s.b_keywtab_ic);
--- a/src/eval.c
+++ b/src/eval.c
@@ -2131,7 +2131,7 @@ list_buf_vars(first)
 {
     char_u	numbuf[NUMBUFLEN];
 
-    list_hashtable_vars(&curbuf->b_vars.dv_hashtab, (char_u *)"b:",
+    list_hashtable_vars(&curbuf->b_vars->dv_hashtab, (char_u *)"b:",
 								 TRUE, first);
 
     sprintf((char *)numbuf, "%ld", (long)curbuf->b_changedtick);
@@ -2146,7 +2146,7 @@ list_buf_vars(first)
 list_win_vars(first)
     int *first;
 {
-    list_hashtable_vars(&curwin->w_vars.dv_hashtab,
+    list_hashtable_vars(&curwin->w_vars->dv_hashtab,
 						 (char_u *)"w:", TRUE, first);
 }
 
@@ -2158,7 +2158,7 @@ list_win_vars(first)
 list_tab_vars(first)
     int *first;
 {
-    list_hashtable_vars(&curtab->tp_vars.dv_hashtab,
+    list_hashtable_vars(&curtab->tp_vars->dv_hashtab,
 						 (char_u *)"t:", TRUE, first);
 }
 #endif
@@ -3948,7 +3948,7 @@ get_user_var_name(xp, idx)
     }
 
     /* b: variables */
-    ht = &curbuf->b_vars.dv_hashtab;
+    ht = &curbuf->b_vars->dv_hashtab;
     if (bdone < ht->ht_used)
     {
 	if (bdone++ == 0)
@@ -3966,7 +3966,7 @@ get_user_var_name(xp, idx)
     }
 
     /* w: variables */
-    ht = &curwin->w_vars.dv_hashtab;
+    ht = &curwin->w_vars->dv_hashtab;
     if (wdone < ht->ht_used)
     {
 	if (wdone++ == 0)
@@ -3980,7 +3980,7 @@ get_user_var_name(xp, idx)
 
 #ifdef FEAT_WINDOWS
     /* t: variables */
-    ht = &curtab->tp_vars.dv_hashtab;
+    ht = &curtab->tp_vars->dv_hashtab;
     if (tdone < ht->ht_used)
     {
 	if (tdone++ == 0)
@@ -6787,16 +6787,16 @@ garbage_collect()
 
     /* buffer-local variables */
     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
-	set_ref_in_ht(&buf->b_vars.dv_hashtab, copyID);
+	set_ref_in_item(&buf->b_bufvar.di_tv, copyID);
 
     /* window-local variables */
     FOR_ALL_TAB_WINDOWS(tp, wp)
-	set_ref_in_ht(&wp->w_vars.dv_hashtab, copyID);
+	set_ref_in_item(&wp->w_winvar.di_tv, copyID);
 
 #ifdef FEAT_WINDOWS
     /* tabpage-local variables */
     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
-	set_ref_in_ht(&tp->tp_vars.dv_hashtab, copyID);
+	set_ref_in_item(&tp->tp_winvar.di_tv, copyID);
 #endif
 
     /* global variables */
@@ -11156,7 +11156,7 @@ f_getbufvar(argvars, rettv)
 		 * find_var_in_ht(). */
 		varname = (char_u *)"b:" + 2;
 	    /* look up the variable */
-	    v = find_var_in_ht(&curbuf->b_vars.dv_hashtab, varname, FALSE);
+	    v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, varname, FALSE);
 	    if (v != NULL)
 		copy_tv(&v->di_tv, rettv);
 	}
@@ -11779,7 +11779,7 @@ f_gettabvar(argvars, rettv)
     if (tp != NULL && varname != NULL)
     {
 	/* look up the variable */
-	v = find_var_in_ht(&tp->tp_vars.dv_hashtab, varname, FALSE);
+	v = find_var_in_ht(&tp->tp_vars->dv_hashtab, varname, FALSE);
 	if (v != NULL)
 	    copy_tv(&v->di_tv, rettv);
 	else if (argvars[2].v_type != VAR_UNKNOWN)
@@ -11935,7 +11935,7 @@ getwinvar(argvars, rettv, off)
 		 * find_var_in_ht(). */
 		varname = (char_u *)"w:" + 2;
 	    /* look up the variable */
-	    v = find_var_in_ht(&win->w_vars.dv_hashtab, varname, FALSE);
+	    v = find_var_in_ht(&win->w_vars->dv_hashtab, varname, FALSE);
 	    if (v != NULL)
 		copy_tv(&v->di_tv, rettv);
 	}
@@ -14333,7 +14333,7 @@ f_mode(argvars, rettv)
     rettv->v_type = VAR_STRING;
 }
 
-#ifdef FEAT_MZSCHEME
+#if defined(FEAT_MZSCHEME) || defined(PROTO)
 /*
  * "mzeval()" function
  */
@@ -20134,12 +20134,12 @@ find_var_ht(name, varname)
 			       || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
 	return NULL;
     if (*name == 'b')				/* buffer variable */
-	return &curbuf->b_vars.dv_hashtab;
+	return &curbuf->b_vars->dv_hashtab;
     if (*name == 'w')				/* window variable */
-	return &curwin->w_vars.dv_hashtab;
+	return &curwin->w_vars->dv_hashtab;
 #ifdef FEAT_WINDOWS
     if (*name == 't')				/* tab page variable */
-	return &curtab->tp_vars.dv_hashtab;
+	return &curtab->tp_vars->dv_hashtab;
 #endif
     if (*name == 'v')				/* v: variable */
 	return &vimvarht;
@@ -20229,6 +20229,19 @@ init_var_dict(dict, dict_var, scope)
 }
 
 /*
+ * Unreference a dictionary initialized by init_var_dict().
+ */
+    void
+unref_var_dict(dict)
+    dict_T	*dict;
+{
+    /* Now the dict needs to be freed if no one else is using it, go back to
+     * normal reference counting. */
+    dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
+    dict_unref(dict);
+}
+
+/*
  * Clean up a list of internal variables.
  * Frees all allocated variables and the value they contain.
  * Clears hashtab "ht", does not free it.
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -8955,8 +8955,8 @@ win_found:
 	    /* Hmm, original window disappeared.  Just use the first one. */
 	    curwin = firstwin;
 # ifdef FEAT_EVAL
-	vars_clear(&aucmd_win->w_vars.dv_hashtab);  /* free all w: variables */
-	hash_init(&aucmd_win->w_vars.dv_hashtab);   /* re-use the hashtab */
+	vars_clear(&aucmd_win->w_vars->dv_hashtab);  /* free all w: variables */
+	hash_init(&aucmd_win->w_vars->dv_hashtab);   /* re-use the hashtab */
 # endif
 #else
 	curwin = aco->save_curwin;
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -24,8 +24,8 @@ list_T *eval_spell_expr __ARGS((char_u *
 int get_spellword __ARGS((list_T *list, char_u **pp));
 typval_T *eval_expr __ARGS((char_u *arg, char_u **nextcmd));
 int call_vim_function __ARGS((char_u *func, int argc, char_u **argv, int safe, int str_arg_only, typval_T *rettv));
+long call_func_retnr __ARGS((char_u *func, int argc, char_u **argv, int safe));
 void *call_func_retstr __ARGS((char_u *func, int argc, char_u **argv, int safe));
-long call_func_retnr __ARGS((char_u *func, int argc, char_u **argv, int safe));
 void *call_func_retlist __ARGS((char_u *func, int argc, char_u **argv, int safe));
 void *save_funccal __ARGS((void));
 void restore_funccal __ARGS((void *vfc));
@@ -95,6 +95,7 @@ char_u *get_tv_string_chk __ARGS((typval
 char_u *get_var_value __ARGS((char_u *name));
 void new_script_vars __ARGS((scid_T id));
 void init_var_dict __ARGS((dict_T *dict, dictitem_T *dict_var, int scope));
+void unref_var_dict __ARGS((dict_T *dict));
 void vars_clear __ARGS((hashtab_T *ht));
 void copy_tv __ARGS((typval_T *from, typval_T *to));
 void ex_echo __ARGS((exarg_T *eap));
--- a/src/structs.h
+++ b/src/structs.h
@@ -1611,7 +1611,7 @@ struct file_buffer
 
 #ifdef FEAT_EVAL
     dictitem_T	b_bufvar;	/* variable for "b:" Dictionary */
-    dict_T	b_vars;		/* internal variables, local to buffer */
+    dict_T	*b_vars;	/* internal variables, local to buffer */
 #endif
 
 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
@@ -1757,7 +1757,7 @@ struct tabpage_S
     frame_T	    *(tp_snapshot[SNAP_COUNT]);  /* window layout snapshots */
 #ifdef FEAT_EVAL
     dictitem_T	    tp_winvar;	    /* variable for "t:" Dictionary */
-    dict_T	    tp_vars;	    /* internal variables, local to tab page */
+    dict_T	    *tp_vars;	    /* internal variables, local to tab page */
 #endif
 };
 
@@ -2080,7 +2080,7 @@ struct window_S
 
 #ifdef FEAT_EVAL
     dictitem_T	w_winvar;	/* variable for "w:" Dictionary */
-    dict_T	w_vars;		/* internal variables, local to window */
+    dict_T	*w_vars;	/* internal variables, local to window */
 #endif
 
 #if defined(FEAT_RIGHTLEFT) && defined(FEAT_FKMAP)
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    893,
+/**/
     892,
 /**/
     891,
--- a/src/window.c
+++ b/src/window.c
@@ -3457,25 +3457,35 @@ win_init_size()
 alloc_tabpage()
 {
     tabpage_T	*tp;
+# ifdef FEAT_GUI
+    int		i;
+# endif
+
 
     tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
-    if (tp != NULL)
-    {
+    if (tp == NULL)
+	return NULL;
+
+# ifdef FEAT_EVAL
+    /* init t: variables */
+    tp->tp_vars = dict_alloc();
+    if (tp->tp_vars == NULL)
+    {
+	vim_free(tp);
+	return NULL;
+    }
+    init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
+# endif
+
 # ifdef FEAT_GUI
-	int	i;
-
-	for (i = 0; i < 3; i++)
-	    tp->tp_prev_which_scrollbars[i] = -1;
+    for (i = 0; i < 3; i++)
+	tp->tp_prev_which_scrollbars[i] = -1;
 # endif
 # ifdef FEAT_DIFF
-	tp->tp_diff_invalid = TRUE;
+    tp->tp_diff_invalid = TRUE;
 # endif
-#ifdef FEAT_EVAL
-	/* init t: variables */
-	init_var_dict(&tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
-#endif
-	tp->tp_ch_used = p_ch;
-    }
+    tp->tp_ch_used = p_ch;
+
     return tp;
 }
 
@@ -3491,7 +3501,9 @@ free_tabpage(tp)
     for (idx = 0; idx < SNAP_COUNT; ++idx)
 	clear_snapshot(tp, idx);
 #ifdef FEAT_EVAL
-    vars_clear(&tp->tp_vars.dv_hashtab);	/* free all t: variables */
+    vars_clear(&tp->tp_vars->dv_hashtab);	/* free all t: variables */
+    hash_init(&tp->tp_vars->dv_hashtab);
+    unref_var_dict(tp->tp_vars);
 #endif
     vim_free(tp);
 }
@@ -4363,71 +4375,79 @@ win_alloc(after, hidden)
      * allocate window structure and linesizes arrays
      */
     new_wp = (win_T *)alloc_clear((unsigned)sizeof(win_T));
-    if (new_wp != NULL && win_alloc_lines(new_wp) == FAIL)
+    if (new_wp == NULL)
+	return NULL;
+
+    if (win_alloc_lines(new_wp) == FAIL)
     {
 	vim_free(new_wp);
-	new_wp = NULL;
-    }
-
-    if (new_wp != NULL)
-    {
+	return NULL;
+    }
+
+#ifdef FEAT_EVAL
+    /* init w: variables */
+    new_wp->w_vars = dict_alloc();
+    if (new_wp->w_vars == NULL)
+    {
+	win_free_lsize(new_wp);
+	vim_free(new_wp);
+	return NULL;
+    }
+    init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
+#endif
+
 #ifdef FEAT_AUTOCMD
-	/* Don't execute autocommands while the window is not properly
-	 * initialized yet.  gui_create_scrollbar() may trigger a FocusGained
-	 * event. */
-	block_autocmds();
-#endif
-	/*
-	 * link the window in the window list
-	 */
+    /* Don't execute autocommands while the window is not properly
+     * initialized yet.  gui_create_scrollbar() may trigger a FocusGained
+     * event. */
+    block_autocmds();
+#endif
+    /*
+     * link the window in the window list
+     */
 #ifdef FEAT_WINDOWS
-	if (!hidden)
-	    win_append(after, new_wp);
+    if (!hidden)
+	win_append(after, new_wp);
 #endif
 #ifdef FEAT_VERTSPLIT
-	new_wp->w_wincol = 0;
-	new_wp->w_width = Columns;
-#endif
-
-	/* position the display and the cursor at the top of the file. */
-	new_wp->w_topline = 1;
+    new_wp->w_wincol = 0;
+    new_wp->w_width = Columns;
+#endif
+
+    /* position the display and the cursor at the top of the file. */
+    new_wp->w_topline = 1;
 #ifdef FEAT_DIFF
-	new_wp->w_topfill = 0;
-#endif
-	new_wp->w_botline = 2;
-	new_wp->w_cursor.lnum = 1;
+    new_wp->w_topfill = 0;
+#endif
+    new_wp->w_botline = 2;
+    new_wp->w_cursor.lnum = 1;
 #ifdef FEAT_SCROLLBIND
-	new_wp->w_scbind_pos = 1;
-#endif
-
-	/* We won't calculate w_fraction until resizing the window */
-	new_wp->w_fraction = 0;
-	new_wp->w_prev_fraction_row = -1;
+    new_wp->w_scbind_pos = 1;
+#endif
+
+    /* We won't calculate w_fraction until resizing the window */
+    new_wp->w_fraction = 0;
+    new_wp->w_prev_fraction_row = -1;
 
 #ifdef FEAT_GUI
-	if (gui.in_use)
-	{
-	    gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
-		    SBAR_LEFT, new_wp);
-	    gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
-		    SBAR_RIGHT, new_wp);
-	}
-#endif
-#ifdef FEAT_EVAL
-	/* init w: variables */
-	init_var_dict(&new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
+    if (gui.in_use)
+    {
+	gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
+		SBAR_LEFT, new_wp);
+	gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
+		SBAR_RIGHT, new_wp);
+    }
 #endif
 #ifdef FEAT_FOLDING
-	foldInitWin(new_wp);
+    foldInitWin(new_wp);
 #endif
 #ifdef FEAT_AUTOCMD
-	unblock_autocmds();
+    unblock_autocmds();
 #endif
 #ifdef FEAT_SEARCH_EXTRA
-	new_wp->w_match_head = NULL;
-	new_wp->w_next_match_id = 4;
-#endif
-    }
+    new_wp->w_match_head = NULL;
+    new_wp->w_next_match_id = 4;
+#endif
     return new_wp;
 }
 
@@ -4488,7 +4508,9 @@ win_free(wp, tp)
     clear_winopt(&wp->w_allbuf_opt);
 
 #ifdef FEAT_EVAL
-    vars_clear(&wp->w_vars.dv_hashtab);	    /* free all w: variables */
+    vars_clear(&wp->w_vars->dv_hashtab);	/* free all w: variables */
+    hash_init(&wp->w_vars->dv_hashtab);
+    unref_var_dict(wp->w_vars);
 #endif
 
     if (prevwin == wp)