mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Test and initial fix for crash with dictwatcherdel
Fixes https://github.com/neovim/neovim/issues/11188.
This commit is contained in:
parent
c20ae3aadb
commit
4c76b1e981
@ -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);
|
||||
}
|
||||
|
||||
@ -1197,7 +1198,11 @@ bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern,
|
||||
}
|
||||
|
||||
QUEUE_REMOVE(w);
|
||||
tv_dict_watcher_free(watcher);
|
||||
if (watcher->busy) {
|
||||
watcher->needs_free = true;
|
||||
} else {
|
||||
tv_dict_watcher_free(watcher);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1268,6 +1273,9 @@ 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) {
|
||||
tv_dict_watcher_free(watcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
tv_dict_unref(dict);
|
||||
|
@ -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
|
||||
|
@ -371,4 +371,24 @@ describe('VimL dictionary notifications', function()
|
||||
eq(1, eval('g:called'))
|
||||
end)
|
||||
|
||||
it('does not crash when using dictwatcherdel in callback', function()
|
||||
source([[
|
||||
let g:d = {}
|
||||
|
||||
function! W(...)
|
||||
call dictwatcherdel(g:d, '*', function('W'))
|
||||
try
|
||||
call dictwatcherdel({}, 'meh', function('tr'))
|
||||
catch
|
||||
let g:exc = v:exception
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
call dictwatcheradd(g:d, '*', function('W'))
|
||||
let g:d.foo = 23
|
||||
]])
|
||||
eq(23, eval('g:d.foo'))
|
||||
eq("Vim(call):Couldn't find a watcher matching key and callback", eval('g:exc'))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user