aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerw7 <erw7.github@gmail.com>2019-09-06 12:38:52 +0900
committererw7 <erw7.github@gmail.com>2020-05-25 18:52:30 +0900
commitc3dab08c8fcbb969805f8b8825475822d5e40469 (patch)
treec803f565cd0ff40300f43483f14198692e7b4619
parent0cab85df4d465fae2973571ebbddbde54d45482b (diff)
downloadrneovim-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.c7
-rw-r--r--src/nvim/eval/userfunc.c13
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;
}