diff options
author | erw7 <erw7.github@gmail.com> | 2019-09-06 12:38:52 +0900 |
---|---|---|
committer | erw7 <erw7.github@gmail.com> | 2020-05-25 18:52:30 +0900 |
commit | c3dab08c8fcbb969805f8b8825475822d5e40469 (patch) | |
tree | c803f565cd0ff40300f43483f14198692e7b4619 | |
parent | 0cab85df4d465fae2973571ebbddbde54d45482b (diff) | |
download | rneovim-c3dab08c8fcbb969805f8b8825475822d5e40469.tar.gz rneovim-c3dab08c8fcbb969805f8b8825475822d5e40469.tar.bz2 rneovim-c3dab08c8fcbb969805f8b8825475822d5e40469.zip |
vim-patch:8.1.1485: double free when garbage_collect() is used in autocommand
Problem: Double free when garbage_collect() is used in autocommand.
Solution: Have garbage collection also set the copyID in funccal_stack.
https://github.com/vim/vim/commit/c07f67ad0e9c48a07d49f2d67eb63e183a22386a
-rw-r--r-- | src/nvim/eval.c | 7 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 13 |
2 files changed, 14 insertions, 6 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b31b6bd0f8..e24605f25f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -439,12 +439,11 @@ void eval_clear(void) xfree(SCRIPT_SV(i)); ga_clear(&ga_scripts); - // functions need to be freed before gargabe collecting, otherwise local - // variables might be freed twice. - free_all_functions(); - // unreferenced lists and dicts (void)garbage_collect(false); + + // functions not garbage collected + free_all_functions(); } #endif diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index de4ca86680..c054433255 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3356,9 +3356,18 @@ bool set_ref_in_call_stack(int copyID) bool abort = false; for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->caller) { - abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); - abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); + abort = abort || set_ref_in_funccal(fc, copyID); } + + // Also go through the funccal_stack. + for (funccal_entry_T *entry = funccal_stack; entry != NULL; + entry = entry->next) { + for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL; + fc = fc->caller) { + abort = abort || set_ref_in_funccal(fc, copyID); + } + } + return abort; } |