diff options
author | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2021-03-31 19:22:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-31 19:22:11 -0400 |
commit | a177820420d3de1614bff01321c0a54a2327fab3 (patch) | |
tree | 54a2ea52ae7ca218f96416ba1ebebd09f10063ba /src/nvim/eval/typval.c | |
parent | d55a69168f0ede6021ffe43dd8c059a350502dbc (diff) | |
parent | 5e4fb9a7dd9392cc59ab6b4f03a9f266c048b86c (diff) | |
download | rneovim-a177820420d3de1614bff01321c0a54a2327fab3.tar.gz rneovim-a177820420d3de1614bff01321c0a54a2327fab3.tar.bz2 rneovim-a177820420d3de1614bff01321c0a54a2327fab3.zip |
Merge pull request #14259 from janlazo/fix-dictwatcherdel-crash
Fix dictwatcherdel crash
Diffstat (limited to 'src/nvim/eval/typval.c')
-rw-r--r-- | src/nvim/eval/typval.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 9be487f4fd..fe3d147040 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1109,6 +1109,7 @@ void tv_dict_watcher_add(dict_T *const dict, const char *const key_pattern, watcher->key_pattern_len = key_pattern_len; watcher->callback = callback; watcher->busy = false; + watcher->needs_free = false; QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node); } @@ -1182,22 +1183,30 @@ bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern, QUEUE *w = NULL; DictWatcher *watcher = NULL; bool matched = false; - QUEUE_FOREACH(w, &dict->watchers) { + bool queue_is_busy = false; + QUEUE_FOREACH(w, &dict->watchers, { watcher = tv_dict_watcher_node_data(w); + if (watcher->busy) { + queue_is_busy = true; + } if (tv_callback_equal(&watcher->callback, &callback) && watcher->key_pattern_len == key_pattern_len && memcmp(watcher->key_pattern, key_pattern, key_pattern_len) == 0) { matched = true; break; } - } + }) if (!matched) { return false; } - QUEUE_REMOVE(w); - tv_dict_watcher_free(watcher); + if (queue_is_busy) { + watcher->needs_free = true; + } else { + QUEUE_REMOVE(w); + tv_dict_watcher_free(watcher); + } return true; } @@ -1258,9 +1267,10 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T rettv; + bool any_needs_free = false; dict->dv_refcount++; QUEUE *w; - QUEUE_FOREACH(w, &dict->watchers) { + QUEUE_FOREACH(w, &dict->watchers, { DictWatcher *watcher = tv_dict_watcher_node_data(w); if (!watcher->busy && tv_dict_watcher_matches(watcher, key)) { rettv = TV_INITIAL_VALUE; @@ -1268,7 +1278,19 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, callback_call(&watcher->callback, 3, argv, &rettv); watcher->busy = false; tv_clear(&rettv); + if (watcher->needs_free) { + any_needs_free = true; + } } + }) + if (any_needs_free) { + QUEUE_FOREACH(w, &dict->watchers, { + DictWatcher *watcher = tv_dict_watcher_node_data(w); + if (watcher->needs_free) { + QUEUE_REMOVE(w); + tv_dict_watcher_free(watcher); + } + }) } tv_dict_unref(dict); |