mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.1.0475: memory not freed on exit when quit in autocmd
Problem: Memory not freed on exit when quit in autocmd. Solution: Remember funccal stack when executing autocmd.
This commit is contained in:
parent
a16bc54503
commit
27e80c885b
12
src/eval.c
12
src/eval.c
@ -859,9 +859,9 @@ eval_to_string_safe(
|
||||
int use_sandbox)
|
||||
{
|
||||
char_u *retval;
|
||||
void *save_funccalp;
|
||||
funccal_entry_T funccal_entry;
|
||||
|
||||
save_funccalp = save_funccal();
|
||||
save_funccal(&funccal_entry);
|
||||
if (use_sandbox)
|
||||
++sandbox;
|
||||
++textlock;
|
||||
@ -869,7 +869,7 @@ eval_to_string_safe(
|
||||
if (use_sandbox)
|
||||
--sandbox;
|
||||
--textlock;
|
||||
restore_funccal(save_funccalp);
|
||||
restore_funccal();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -8532,7 +8532,7 @@ read_viminfo_varlist(vir_T *virp, int writing)
|
||||
char_u *tab;
|
||||
int type = VAR_NUMBER;
|
||||
typval_T tv;
|
||||
void *save_funccal;
|
||||
funccal_entry_T funccal_entry;
|
||||
|
||||
if (!writing && (find_viminfo_parameter('!') != NULL))
|
||||
{
|
||||
@ -8581,9 +8581,9 @@ read_viminfo_varlist(vir_T *virp, int writing)
|
||||
}
|
||||
|
||||
/* when in a function use global variables */
|
||||
save_funccal = clear_current_funccal();
|
||||
save_funccal(&funccal_entry);
|
||||
set_var(virp->vir_line + 1, &tv, FALSE);
|
||||
restore_current_funccal(save_funccal);
|
||||
restore_funccal();
|
||||
|
||||
if (tv.v_type == VAR_STRING)
|
||||
vim_free(tv.vval.v_string);
|
||||
|
@ -4344,7 +4344,7 @@ do_source(
|
||||
#ifdef FEAT_EVAL
|
||||
sctx_T save_current_sctx;
|
||||
static scid_T last_current_SID = 0;
|
||||
void *save_funccalp;
|
||||
funccal_entry_T funccalp_entry;
|
||||
int save_debug_break_level = debug_break_level;
|
||||
scriptitem_T *si = NULL;
|
||||
# ifdef UNIX
|
||||
@ -4506,7 +4506,7 @@ do_source(
|
||||
|
||||
/* Don't use local function variables, if called from a function.
|
||||
* Also starts profiling timer for nested script. */
|
||||
save_funccalp = save_funccal();
|
||||
save_funccal(&funccalp_entry);
|
||||
|
||||
/*
|
||||
* Check if this script was sourced before to finds its SID.
|
||||
@ -4665,7 +4665,7 @@ do_source(
|
||||
#ifdef FEAT_EVAL
|
||||
almosttheend:
|
||||
current_sctx = save_current_sctx;
|
||||
restore_funccal(save_funccalp);
|
||||
restore_funccal();
|
||||
# ifdef FEAT_PROFILE
|
||||
if (do_profiling == PROF_YES)
|
||||
prof_child_exit(&wait_start); /* leaving a child now */
|
||||
|
@ -9400,7 +9400,7 @@ apply_autocmds_group(
|
||||
AutoPat *ap;
|
||||
#ifdef FEAT_EVAL
|
||||
sctx_T save_current_sctx;
|
||||
void *save_funccalp;
|
||||
funccal_entry_T funccal_entry;
|
||||
char_u *save_cmdarg;
|
||||
long save_cmdbang;
|
||||
#endif
|
||||
@ -9615,8 +9615,8 @@ apply_autocmds_group(
|
||||
prof_child_enter(&wait_time); /* doesn't count for the caller itself */
|
||||
# endif
|
||||
|
||||
/* Don't use local function variables, if called from a function */
|
||||
save_funccalp = save_funccal();
|
||||
// Don't use local function variables, if called from a function.
|
||||
save_funccal(&funccal_entry);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -9713,7 +9713,7 @@ apply_autocmds_group(
|
||||
autocmd_match = save_autocmd_match;
|
||||
#ifdef FEAT_EVAL
|
||||
current_sctx = save_current_sctx;
|
||||
restore_funccal(save_funccalp);
|
||||
restore_funccal();
|
||||
# ifdef FEAT_PROFILE
|
||||
if (do_profiling == PROF_YES)
|
||||
prof_child_exit(&wait_time);
|
||||
|
20
src/main.c
20
src/main.c
@ -1717,7 +1717,7 @@ get_number_arg(
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for: [r][e][g][vi|vim|view][diff][ex[im]]
|
||||
* Check for: [r][e][g][vi|vim|view][diff][ex[im]] (sort of)
|
||||
* If the executable name starts with "r" we disable shell commands.
|
||||
* If the next character is "e" we run in Easy mode.
|
||||
* If the next character is "g" we run the GUI version.
|
||||
@ -1788,7 +1788,7 @@ parse_command_name(mparm_T *parmp)
|
||||
else if (STRNICMP(initstr, "vim", 3) == 0)
|
||||
initstr += 3;
|
||||
|
||||
/* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */
|
||||
// Catch "[r][g]vimdiff" and "[r][g]viewdiff".
|
||||
if (STRICMP(initstr, "diff") == 0)
|
||||
{
|
||||
#ifdef FEAT_DIFF
|
||||
@ -1800,13 +1800,15 @@ parse_command_name(mparm_T *parmp)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Checking for "ex" here may catch some weir names, such as "vimex" or
|
||||
// "viewex", we assume the user knows that.
|
||||
if (STRNICMP(initstr, "ex", 2) == 0)
|
||||
{
|
||||
if (STRNICMP(initstr + 2, "im", 2) == 0)
|
||||
exmode_active = EXMODE_VIM;
|
||||
else
|
||||
exmode_active = EXMODE_NORMAL;
|
||||
change_compatible(TRUE); /* set 'compatible' */
|
||||
change_compatible(TRUE); // set 'compatible'
|
||||
}
|
||||
}
|
||||
|
||||
@ -4188,12 +4190,16 @@ eval_client_expr_to_string(char_u *expr)
|
||||
char_u *res;
|
||||
int save_dbl = debug_break_level;
|
||||
int save_ro = redir_off;
|
||||
void *fc = NULL;
|
||||
funccal_entry_T funccal_entry;
|
||||
int did_save_funccal = FALSE;
|
||||
|
||||
/* Evaluate the expression at the toplevel, don't use variables local to
|
||||
* the calling function. Except when in debug mode. */
|
||||
if (!debug_mode)
|
||||
fc = clear_current_funccal();
|
||||
{
|
||||
save_funccal(&funccal_entry);
|
||||
did_save_funccal = TRUE;
|
||||
}
|
||||
|
||||
/* Disable debugging, otherwise Vim hangs, waiting for "cont" to be
|
||||
* typed. */
|
||||
@ -4210,8 +4216,8 @@ eval_client_expr_to_string(char_u *expr)
|
||||
--emsg_silent;
|
||||
if (emsg_silent < 0)
|
||||
emsg_silent = 0;
|
||||
if (fc != NULL)
|
||||
restore_current_funccal(fc);
|
||||
if (did_save_funccal)
|
||||
restore_funccal();
|
||||
|
||||
/* A client can tell us to redraw, but not to display the cursor, so do
|
||||
* that here. */
|
||||
|
@ -39,15 +39,13 @@ linenr_T *func_breakpoint(void *cookie);
|
||||
int *func_dbg_tick(void *cookie);
|
||||
int func_level(void *cookie);
|
||||
int current_func_returned(void);
|
||||
void *save_funccal(void);
|
||||
void restore_funccal(void *vfc);
|
||||
void save_funccal(funccal_entry_T *entry);
|
||||
void restore_funccal(void);
|
||||
int free_unref_funccal(int copyID, int testing);
|
||||
hashtab_T *get_funccal_local_ht(void);
|
||||
dictitem_T *get_funccal_local_var(void);
|
||||
hashtab_T *get_funccal_args_ht(void);
|
||||
dictitem_T *get_funccal_args_var(void);
|
||||
void *clear_current_funccal(void);
|
||||
void restore_current_funccal(void *f);
|
||||
void list_func_vars(int *first);
|
||||
dict_T *get_current_funccal_dict(hashtab_T *ht);
|
||||
hashitem_T *find_hi_in_scoped_ht(char_u *name, hashtab_T **pht);
|
||||
|
@ -1354,7 +1354,7 @@ typedef struct
|
||||
int uf_cleared; /* func_clear() was already called */
|
||||
garray_T uf_args; /* arguments */
|
||||
garray_T uf_lines; /* function lines */
|
||||
#ifdef FEAT_PROFILE
|
||||
# ifdef FEAT_PROFILE
|
||||
int uf_profiling; /* TRUE when func is being profiled */
|
||||
int uf_prof_initialized;
|
||||
/* profiling the function as a whole */
|
||||
@ -1371,7 +1371,7 @@ typedef struct
|
||||
proftime_T uf_tml_wait; /* start wait time for current line */
|
||||
int uf_tml_idx; /* index of line being timed; -1 if none */
|
||||
int uf_tml_execed; /* line being timed was executed */
|
||||
#endif
|
||||
# endif
|
||||
sctx_T uf_script_ctx; /* SCTX where function was defined,
|
||||
used for s: variables */
|
||||
int uf_refcount; /* reference count, see func_name_refcount() */
|
||||
@ -1429,6 +1429,12 @@ typedef struct
|
||||
dictitem_T *fd_di; /* Dictionary item used */
|
||||
} funcdict_T;
|
||||
|
||||
typedef struct funccal_entry funccal_entry_T;
|
||||
struct funccal_entry {
|
||||
void *top_funccal;
|
||||
funccal_entry_T *next;
|
||||
};
|
||||
|
||||
#else
|
||||
/* dummy typedefs for function prototypes */
|
||||
typedef struct
|
||||
|
@ -1175,6 +1175,33 @@ func_name_refcount(char_u *name)
|
||||
return isdigit(*name) || *name == '<';
|
||||
}
|
||||
|
||||
static funccal_entry_T *funccal_stack = NULL;
|
||||
|
||||
/*
|
||||
* Save the current function call pointer, and set it to NULL.
|
||||
* Used when executing autocommands and for ":source".
|
||||
*/
|
||||
void
|
||||
save_funccal(funccal_entry_T *entry)
|
||||
{
|
||||
entry->top_funccal = current_funccal;
|
||||
entry->next = funccal_stack;
|
||||
funccal_stack = entry;
|
||||
current_funccal = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
restore_funccal(void)
|
||||
{
|
||||
if (funccal_stack == NULL)
|
||||
IEMSG("INTERNAL: restore_funccal()");
|
||||
else
|
||||
{
|
||||
current_funccal = funccal_stack->top_funccal;
|
||||
funccal_stack = funccal_stack->next;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EXITFREE) || defined(PROTO)
|
||||
void
|
||||
free_all_functions(void)
|
||||
@ -1185,11 +1212,13 @@ free_all_functions(void)
|
||||
long_u todo = 1;
|
||||
long_u used;
|
||||
|
||||
/* Clean up the call stack. */
|
||||
/* Clean up the current_funccal chain and the funccal stack. */
|
||||
while (current_funccal != NULL)
|
||||
{
|
||||
clear_tv(current_funccal->rettv);
|
||||
cleanup_function_call(current_funccal);
|
||||
if (current_funccal == NULL && funccal_stack != NULL)
|
||||
restore_funccal();
|
||||
}
|
||||
|
||||
/* First clear what the functions contain. Since this may lower the
|
||||
@ -3578,27 +3607,6 @@ current_func_returned(void)
|
||||
return current_funccal->returned;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the current function call pointer, and set it to NULL.
|
||||
* Used when executing autocommands and for ":source".
|
||||
*/
|
||||
void *
|
||||
save_funccal(void)
|
||||
{
|
||||
funccall_T *fc = current_funccal;
|
||||
|
||||
current_funccal = NULL;
|
||||
return (void *)fc;
|
||||
}
|
||||
|
||||
void
|
||||
restore_funccal(void *vfc)
|
||||
{
|
||||
funccall_T *fc = (funccall_T *)vfc;
|
||||
|
||||
current_funccal = fc;
|
||||
}
|
||||
|
||||
int
|
||||
free_unref_funccal(int copyID, int testing)
|
||||
{
|
||||
@ -3701,25 +3709,6 @@ get_funccal_args_var()
|
||||
return &get_funccal()->l_avars_var;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the current_funccal and return the old value.
|
||||
* Caller is expected to invoke restore_current_funccal().
|
||||
*/
|
||||
void *
|
||||
clear_current_funccal()
|
||||
{
|
||||
funccall_T *f = current_funccal;
|
||||
|
||||
current_funccal = NULL;
|
||||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
restore_current_funccal(void *f)
|
||||
{
|
||||
current_funccal = f;
|
||||
}
|
||||
|
||||
/*
|
||||
* List function variables, if there is a function.
|
||||
*/
|
||||
|
@ -792,6 +792,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
475,
|
||||
/**/
|
||||
474,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user