# HG changeset patch # User Bram Moolenaar # Date 1366021656 -7200 # Node ID dc3efb6d5a0821c79f939db8e3b77a714292195c # Parent afcc61d241293ca083e5e4373eb9bab3293c6337 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) diff --git a/src/buffer.c b/src/buffer.c --- 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); diff --git a/src/eval.c b/src/eval.c --- 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. diff --git a/src/fileio.c b/src/fileio.c --- 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; diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- 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)); diff --git a/src/structs.h b/src/structs.h --- 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) diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/window.c b/src/window.c --- 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)