aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval.c
diff options
context:
space:
mode:
authorJan Edmund Lazo <jan.lazo@mail.utoronto.ca>2021-03-31 19:22:11 -0400
committerGitHub <noreply@github.com>2021-03-31 19:22:11 -0400
commita177820420d3de1614bff01321c0a54a2327fab3 (patch)
tree54a2ea52ae7ca218f96416ba1ebebd09f10063ba /src/nvim/eval/typval.c
parentd55a69168f0ede6021ffe43dd8c059a350502dbc (diff)
parent5e4fb9a7dd9392cc59ab6b4f03a9f266c048b86c (diff)
downloadrneovim-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.c32
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);