mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 22:18:33 +00:00
vim-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.
27e80c885b
This commit is contained in:
@@ -871,17 +871,19 @@ char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert)
|
|||||||
char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox)
|
char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox)
|
||||||
{
|
{
|
||||||
char_u *retval;
|
char_u *retval;
|
||||||
void *save_funccalp;
|
funccal_entry_T funccal_entry;
|
||||||
|
|
||||||
save_funccalp = save_funccal();
|
save_funccal(&funccal_entry);
|
||||||
if (use_sandbox)
|
if (use_sandbox) {
|
||||||
++sandbox;
|
sandbox++;
|
||||||
++textlock;
|
}
|
||||||
retval = eval_to_string(arg, nextcmd, FALSE);
|
textlock++;
|
||||||
if (use_sandbox)
|
retval = eval_to_string(arg, nextcmd, false);
|
||||||
--sandbox;
|
if (use_sandbox) {
|
||||||
--textlock;
|
sandbox--;
|
||||||
restore_funccal(save_funccalp);
|
}
|
||||||
|
textlock--;
|
||||||
|
restore_funccal();
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9747,9 +9749,11 @@ const void *var_shada_iter(const void *const iter, const char **const name,
|
|||||||
|
|
||||||
void var_set_global(const char *const name, typval_T vartv)
|
void var_set_global(const char *const name, typval_T vartv)
|
||||||
{
|
{
|
||||||
funccall_T *const saved_funccal = (funccall_T *)save_funccal();
|
funccal_entry_T funccall_entry;
|
||||||
|
|
||||||
|
save_funccal(&funccall_entry);
|
||||||
set_var(name, strlen(name), &vartv, false);
|
set_var(name, strlen(name), &vartv, false);
|
||||||
restore_funccal(saved_funccal);
|
restore_funccal();
|
||||||
}
|
}
|
||||||
|
|
||||||
int store_session_globals(FILE *fd)
|
int store_session_globals(FILE *fd)
|
||||||
@@ -10305,8 +10309,10 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
|
|||||||
.autocmd_fname = autocmd_fname,
|
.autocmd_fname = autocmd_fname,
|
||||||
.autocmd_match = autocmd_match,
|
.autocmd_match = autocmd_match,
|
||||||
.autocmd_bufnr = autocmd_bufnr,
|
.autocmd_bufnr = autocmd_bufnr,
|
||||||
.funccalp = save_funccal()
|
.funccalp = (void *)get_current_funccal()
|
||||||
};
|
};
|
||||||
|
funccal_entry_T funccal_entry;
|
||||||
|
save_funccal(&funccal_entry);
|
||||||
provider_call_nesting++;
|
provider_call_nesting++;
|
||||||
|
|
||||||
typval_T argvars[3] = {
|
typval_T argvars[3] = {
|
||||||
@@ -10333,7 +10339,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
|
|||||||
|
|
||||||
tv_list_unref(arguments);
|
tv_list_unref(arguments);
|
||||||
// Restore caller scope information
|
// Restore caller scope information
|
||||||
restore_funccal(provider_caller_scope.funccalp);
|
restore_funccal();
|
||||||
provider_caller_scope = saved_provider_caller_scope;
|
provider_caller_scope = saved_provider_caller_scope;
|
||||||
provider_call_nesting--;
|
provider_call_nesting--;
|
||||||
assert(provider_call_nesting >= 0);
|
assert(provider_call_nesting >= 0);
|
||||||
|
@@ -7219,7 +7219,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match;
|
uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match;
|
||||||
linenr_T save_sourcing_lnum;
|
linenr_T save_sourcing_lnum;
|
||||||
int save_autocmd_bufnr;
|
int save_autocmd_bufnr;
|
||||||
void *save_funccalp;
|
funccal_entry_T funccal_entry;
|
||||||
|
|
||||||
if (l_provider_call_nesting) {
|
if (l_provider_call_nesting) {
|
||||||
// If this is called from a provider function, restore the scope
|
// If this is called from a provider function, restore the scope
|
||||||
@@ -7230,7 +7230,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
save_autocmd_fname = autocmd_fname;
|
save_autocmd_fname = autocmd_fname;
|
||||||
save_autocmd_match = autocmd_match;
|
save_autocmd_match = autocmd_match;
|
||||||
save_autocmd_bufnr = autocmd_bufnr;
|
save_autocmd_bufnr = autocmd_bufnr;
|
||||||
save_funccalp = save_funccal();
|
save_funccal(&funccal_entry);
|
||||||
|
|
||||||
current_sctx = provider_caller_scope.script_ctx;
|
current_sctx = provider_caller_scope.script_ctx;
|
||||||
sourcing_name = provider_caller_scope.sourcing_name;
|
sourcing_name = provider_caller_scope.sourcing_name;
|
||||||
@@ -7238,7 +7238,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
autocmd_fname = provider_caller_scope.autocmd_fname;
|
autocmd_fname = provider_caller_scope.autocmd_fname;
|
||||||
autocmd_match = provider_caller_scope.autocmd_match;
|
autocmd_match = provider_caller_scope.autocmd_match;
|
||||||
autocmd_bufnr = provider_caller_scope.autocmd_bufnr;
|
autocmd_bufnr = provider_caller_scope.autocmd_bufnr;
|
||||||
restore_funccal(provider_caller_scope.funccalp);
|
set_current_funccal((funccall_T *)(provider_caller_scope.funccalp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7256,7 +7256,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
autocmd_fname = save_autocmd_fname;
|
autocmd_fname = save_autocmd_fname;
|
||||||
autocmd_match = save_autocmd_match;
|
autocmd_match = save_autocmd_match;
|
||||||
autocmd_bufnr = save_autocmd_bufnr;
|
autocmd_bufnr = save_autocmd_bufnr;
|
||||||
restore_funccal(save_funccalp);
|
restore_funccal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ERROR_SET(&err)) {
|
if (ERROR_SET(&err)) {
|
||||||
|
@@ -1106,21 +1106,26 @@ static bool func_name_refcount(char_u *name)
|
|||||||
return isdigit(*name) || *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(void)
|
|
||||||
{
|
|
||||||
funccall_T *fc = current_funccal;
|
|
||||||
|
|
||||||
|
// 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;
|
current_funccal = NULL;
|
||||||
return (void *)fc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_funccal(void *vfc)
|
void restore_funccal(void)
|
||||||
{
|
{
|
||||||
current_funccal = (funccall_T *)vfc;
|
if (funccal_stack == NULL) {
|
||||||
|
IEMSG("INTERNAL: restore_funccal()");
|
||||||
|
} else {
|
||||||
|
current_funccal = funccal_stack->top_funccal;
|
||||||
|
funccal_stack = funccal_stack->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funccall_T *get_current_funccal(void)
|
funccall_T *get_current_funccal(void)
|
||||||
@@ -1128,6 +1133,11 @@ funccall_T *get_current_funccal(void)
|
|||||||
return current_funccal;
|
return current_funccal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_current_funccal(funccall_T *fc)
|
||||||
|
{
|
||||||
|
current_funccal = fc;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE)
|
#if defined(EXITFREE)
|
||||||
void free_all_functions(void)
|
void free_all_functions(void)
|
||||||
{
|
{
|
||||||
@@ -1137,10 +1147,13 @@ void free_all_functions(void)
|
|||||||
uint64_t todo = 1;
|
uint64_t todo = 1;
|
||||||
uint64_t used;
|
uint64_t used;
|
||||||
|
|
||||||
// Clean up the call stack.
|
// Clean up the current_funccal chain and the funccal stack.
|
||||||
while (current_funccal != NULL) {
|
while (current_funccal != NULL) {
|
||||||
tv_clear(current_funccal->rettv);
|
tv_clear(current_funccal->rettv);
|
||||||
cleanup_function_call(current_funccal);
|
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
|
// First clear what the functions contain. Since this may lower the
|
||||||
|
@@ -11,6 +11,12 @@ typedef struct {
|
|||||||
dictitem_T *fd_di; ///< Dictionary item used.
|
dictitem_T *fd_di; ///< Dictionary item used.
|
||||||
} funcdict_T;
|
} funcdict_T;
|
||||||
|
|
||||||
|
typedef struct funccal_entry funccal_entry_T;
|
||||||
|
struct funccal_entry {
|
||||||
|
void *top_funccal;
|
||||||
|
funccal_entry_T *next;
|
||||||
|
};
|
||||||
|
|
||||||
/// errors for when calling a function
|
/// errors for when calling a function
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ERROR_UNKNOWN = 0,
|
ERROR_UNKNOWN = 0,
|
||||||
|
@@ -3106,7 +3106,6 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
|
|||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
static scid_T last_current_SID = 0;
|
static scid_T last_current_SID = 0;
|
||||||
static int last_current_SID_seq = 0;
|
static int last_current_SID_seq = 0;
|
||||||
void *save_funccalp;
|
|
||||||
int save_debug_break_level = debug_break_level;
|
int save_debug_break_level = debug_break_level;
|
||||||
scriptitem_T *si = NULL;
|
scriptitem_T *si = NULL;
|
||||||
proftime_T wait_start;
|
proftime_T wait_start;
|
||||||
@@ -3227,7 +3226,8 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
|
|||||||
|
|
||||||
// Don't use local function variables, if called from a function.
|
// Don't use local function variables, if called from a function.
|
||||||
// Also starts profiling timer for nested script.
|
// Also starts profiling timer for nested script.
|
||||||
save_funccalp = save_funccal();
|
funccal_entry_T funccalp_entry;
|
||||||
|
save_funccal(&funccalp_entry);
|
||||||
|
|
||||||
// Check if this script was sourced before to finds its SID.
|
// Check if this script was sourced before to finds its SID.
|
||||||
// If it's new, generate a new SID.
|
// If it's new, generate a new SID.
|
||||||
@@ -3352,7 +3352,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_sctx = save_current_sctx;
|
current_sctx = save_current_sctx;
|
||||||
restore_funccal(save_funccalp);
|
restore_funccal();
|
||||||
if (l_do_profiling == PROF_YES) {
|
if (l_do_profiling == PROF_YES) {
|
||||||
prof_child_exit(&wait_start); // leaving a child now
|
prof_child_exit(&wait_start); // leaving a child now
|
||||||
}
|
}
|
||||||
|
@@ -6736,7 +6736,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|
|||||||
static int nesting = 0;
|
static int nesting = 0;
|
||||||
AutoPatCmd patcmd;
|
AutoPatCmd patcmd;
|
||||||
AutoPat *ap;
|
AutoPat *ap;
|
||||||
void *save_funccalp;
|
|
||||||
char_u *save_cmdarg;
|
char_u *save_cmdarg;
|
||||||
long save_cmdbang;
|
long save_cmdbang;
|
||||||
static int filechangeshell_busy = FALSE;
|
static int filechangeshell_busy = FALSE;
|
||||||
@@ -6926,8 +6925,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|
|||||||
if (do_profiling == PROF_YES)
|
if (do_profiling == PROF_YES)
|
||||||
prof_child_enter(&wait_time); /* doesn't count for the caller itself */
|
prof_child_enter(&wait_time); /* doesn't count for the caller itself */
|
||||||
|
|
||||||
/* Don't use local function variables, if called from a function */
|
// Don't use local function variables, if called from a function.
|
||||||
save_funccalp = save_funccal();
|
funccal_entry_T funccal_entry;
|
||||||
|
save_funccal(&funccal_entry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When starting to execute autocommands, save the search patterns.
|
* When starting to execute autocommands, save the search patterns.
|
||||||
@@ -7016,9 +7016,10 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|
|||||||
autocmd_bufnr = save_autocmd_bufnr;
|
autocmd_bufnr = save_autocmd_bufnr;
|
||||||
autocmd_match = save_autocmd_match;
|
autocmd_match = save_autocmd_match;
|
||||||
current_sctx = save_current_sctx;
|
current_sctx = save_current_sctx;
|
||||||
restore_funccal(save_funccalp);
|
restore_funccal();
|
||||||
if (do_profiling == PROF_YES)
|
if (do_profiling == PROF_YES) {
|
||||||
prof_child_exit(&wait_time);
|
prof_child_exit(&wait_time);
|
||||||
|
}
|
||||||
KeyTyped = save_KeyTyped;
|
KeyTyped = save_KeyTyped;
|
||||||
xfree(fname);
|
xfree(fname);
|
||||||
xfree(sfname);
|
xfree(sfname);
|
||||||
|
Reference in New Issue
Block a user