diff options
author | erw7 <erw7.github@gmail.com> | 2019-12-02 19:09:30 +0900 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2019-12-02 02:09:30 -0800 |
commit | ab860cb5f6c749b937e0986167702a36e45000ca (patch) | |
tree | 0b0c700e09bdd0de52f27c25415f58bd1868722d | |
parent | 735d89d09e5cf50886b927ce4ec93b9098da259d (diff) | |
download | rneovim-ab860cb5f6c749b937e0986167702a36e45000ca.tar.gz rneovim-ab860cb5f6c749b937e0986167702a36e45000ca.tar.bz2 rneovim-ab860cb5f6c749b937e0986167702a36e45000ca.zip |
dictwatcher: fix use-after-free #11495
fixes #11494
-rw-r--r-- | src/nvim/eval/typval.c | 2 | ||||
-rw-r--r-- | test/functional/ex_cmds/dict_notifications_spec.lua | 14 |
2 files changed, 16 insertions, 0 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 106b8f6eed..72ee45a03a 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1200,6 +1200,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T rettv; + dict->dv_refcount++; QUEUE *w; QUEUE_FOREACH(w, &dict->watchers) { DictWatcher *watcher = tv_dict_watcher_node_data(w); @@ -1211,6 +1212,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, tv_clear(&rettv); } } + tv_dict_unref(dict); for (size_t i = 1; i < ARRAY_SIZE(argv); i++) { tv_clear(argv + i); diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua index 48e7e05e4c..5c67431221 100644 --- a/test/functional/ex_cmds/dict_notifications_spec.lua +++ b/test/functional/ex_cmds/dict_notifications_spec.lua @@ -357,4 +357,18 @@ describe('VimL dictionary notifications', function() eq(2, eval('1+1')) -- Still alive? end) + it('does not cause use-after-free when unletting from callback', function() + source([[ + let g:called = 0 + function W(...) abort + unlet g:d + let g:called = 1 + endfunction + let g:d = {} + call dictwatcheradd(g:d, '*', function('W')) + let g:d.foo = 123 + ]]) + eq(1, eval('g:called')) + end) + end) |