mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.0.0535: leak when exiting user function (#8574)
Problem: Memory leak when exiting from within a user function.
Solution: Clear the function call stack on exit.
6914c64ee5
This commit is contained in:
parent
89cb304ea0
commit
83be7cec98
@ -693,8 +693,8 @@ int func_level(void *cookie)
|
|||||||
/* pointer to funccal for currently active function */
|
/* pointer to funccal for currently active function */
|
||||||
funccall_T *current_funccal = NULL;
|
funccall_T *current_funccal = NULL;
|
||||||
|
|
||||||
/* pointer to list of previously used funccal, still around because some
|
// Pointer to list of previously used funccal, still around because some
|
||||||
* item in it is still being used. */
|
// item in it is still being used.
|
||||||
funccall_T *previous_funccal = NULL;
|
funccall_T *previous_funccal = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -20506,6 +20506,12 @@ void free_all_functions(void)
|
|||||||
uint64_t todo = 1;
|
uint64_t todo = 1;
|
||||||
uint64_t used;
|
uint64_t used;
|
||||||
|
|
||||||
|
// Clean up the call stack.
|
||||||
|
while (current_funccal != NULL) {
|
||||||
|
tv_clear(current_funccal->rettv);
|
||||||
|
cleanup_function_call(current_funccal);
|
||||||
|
}
|
||||||
|
|
||||||
// First clear what the functions contain. Since this may lower the
|
// First clear what the functions contain. Since this may lower the
|
||||||
// reference count of a function, it may also free a function and change
|
// reference count of a function, it may also free a function and change
|
||||||
// the hash table. Restart if that happens.
|
// the hash table. Restart if that happens.
|
||||||
@ -21485,30 +21491,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
|
|||||||
}
|
}
|
||||||
|
|
||||||
did_emsg |= save_did_emsg;
|
did_emsg |= save_did_emsg;
|
||||||
current_funccal = fc->caller;
|
depth--;
|
||||||
--depth;
|
|
||||||
|
|
||||||
// If the a:000 list and the l: and a: dicts are not referenced and there
|
cleanup_function_call(fc);
|
||||||
// is no closure using it, we can free the funccall_T and what's in it.
|
|
||||||
if (!fc_referenced(fc)) {
|
|
||||||
free_funccal(fc, false);
|
|
||||||
} else {
|
|
||||||
// "fc" is still in use. This can happen when returning "a:000",
|
|
||||||
// assigning "l:" to a global variable or defining a closure.
|
|
||||||
// Link "fc" in the list for garbage collection later.
|
|
||||||
fc->caller = previous_funccal;
|
|
||||||
previous_funccal = fc;
|
|
||||||
|
|
||||||
// Make a copy of the a: variables, since we didn't do that above.
|
|
||||||
TV_DICT_ITER(&fc->l_avars, di, {
|
|
||||||
tv_copy(&di->di_tv, &di->di_tv);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make a copy of the a:000 items, since we didn't do that above.
|
|
||||||
TV_LIST_ITER(&fc->l_varlist, li, {
|
|
||||||
tv_copy(TV_LIST_ITEM_TV(li), TV_LIST_ITEM_TV(li));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) {
|
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) {
|
||||||
// Function was unreferenced while being used, free it now.
|
// Function was unreferenced while being used, free it now.
|
||||||
@ -21601,6 +21586,35 @@ free_funccal(
|
|||||||
xfree(fc);
|
xfree(fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle the last part of returning from a function: free the local hashtable.
|
||||||
|
/// Unless it is still in use by a closure.
|
||||||
|
static void cleanup_function_call(funccall_T *fc)
|
||||||
|
{
|
||||||
|
current_funccal = fc->caller;
|
||||||
|
|
||||||
|
// If the a:000 list and the l: and a: dicts are not referenced and there
|
||||||
|
// is no closure using it, we can free the funccall_T and what's in it.
|
||||||
|
if (!fc_referenced(fc)) {
|
||||||
|
free_funccal(fc, false);
|
||||||
|
} else {
|
||||||
|
// "fc" is still in use. This can happen when returning "a:000",
|
||||||
|
// assigning "l:" to a global variable or defining a closure.
|
||||||
|
// Link "fc" in the list for garbage collection later.
|
||||||
|
fc->caller = previous_funccal;
|
||||||
|
previous_funccal = fc;
|
||||||
|
|
||||||
|
// Make a copy of the a: variables, since we didn't do that above.
|
||||||
|
TV_DICT_ITER(&fc->l_avars, di, {
|
||||||
|
tv_copy(&di->di_tv, &di->di_tv);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make a copy of the a:000 items, since we didn't do that above.
|
||||||
|
TV_LIST_ITER(&fc->l_varlist, li, {
|
||||||
|
tv_copy(TV_LIST_ITEM_TV(li), TV_LIST_ITEM_TV(li));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a number variable "name" to dict "dp" with value "nr".
|
* Add a number variable "name" to dict "dp" with value "nr".
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user