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 | |
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')
-rw-r--r-- | src/nvim/eval/typval.c | 32 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 1 |
2 files changed, 28 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); diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 531b17cb59..2b4612016b 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -89,6 +89,7 @@ typedef struct dict_watcher { size_t key_pattern_len; QUEUE node; bool busy; // prevent recursion if the dict is changed in the callback + bool needs_free; } DictWatcher; /// Bool variable values |