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->key_pattern_len = key_pattern_len;
|
||||||
watcher->callback = callback;
|
watcher->callback = callback;
|
||||||
watcher->busy = false;
|
watcher->busy = false;
|
||||||
|
watcher->needs_free = false;
|
||||||
QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node);
|
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);
|
QUEUE_REMOVE(w);
|
||||||
tv_dict_watcher_free(watcher);
|
if (watcher->busy) {
|
||||||
|
watcher->needs_free = true;
|
||||||
|
} else {
|
||||||
|
tv_dict_watcher_free(watcher);
|
||||||
|
}
|
||||||
return true;
|
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);
|
callback_call(&watcher->callback, 3, argv, &rettv);
|
||||||
watcher->busy = false;
|
watcher->busy = false;
|
||||||
tv_clear(&rettv);
|
tv_clear(&rettv);
|
||||||
|
if (watcher->needs_free) {
|
||||||
|
tv_dict_watcher_free(watcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tv_dict_unref(dict);
|
tv_dict_unref(dict);
|
||||||
|
@ -89,6 +89,7 @@ typedef struct dict_watcher {
|
|||||||
size_t key_pattern_len;
|
size_t key_pattern_len;
|
||||||
QUEUE node;
|
QUEUE node;
|
||||||
bool busy; // prevent recursion if the dict is changed in the callback
|
bool busy; // prevent recursion if the dict is changed in the callback
|
||||||
|
bool needs_free;
|
||||||
} DictWatcher;
|
} DictWatcher;
|
||||||
|
|
||||||
/// Bool variable values
|
/// Bool variable values
|
||||||
|
@ -371,4 +371,24 @@ describe('VimL dictionary notifications', function()
|
|||||||
eq(1, eval('g:called'))
|
eq(1, eval('g:called'))
|
||||||
end)
|
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)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user