diff options
author | Scott Prager <splinterofchaos@gmail.com> | 2015-04-06 17:47:08 -0400 |
---|---|---|
committer | Scott Prager <splinterofchaos@gmail.com> | 2015-04-07 16:05:00 -0400 |
commit | 8cac2eea751379e0195b5160f9d14d19f8866e71 (patch) | |
tree | 1b59157c5f89cc8db04422d6df715cf59defde27 /src | |
parent | 013bd4461d95341fbd7c2f742844666a5e966f94 (diff) | |
download | rneovim-8cac2eea751379e0195b5160f9d14d19f8866e71.tar.gz rneovim-8cac2eea751379e0195b5160f9d14d19f8866e71.tar.bz2 rneovim-8cac2eea751379e0195b5160f9d14d19f8866e71.zip |
term: ensure term->buf is valid
The fallowing test (reduced), submitted by @mhinz may free term->buf,
leaving the pointer dangling.
```vim
let s:buf = -1
function! s:exit_handler()
execute 'bdelete!' s:buf
endfunction
vnew
let s:buf = bufnr('%')
let id = termopen('sleep 1', { 'on_exit': function('s:exit_handler') })
call s:test()
```
When the buffer is known to be closing, set term->buf to NULL, and check
buf_valid() in on_refresh().
Helped-by: Marco Hinz (@mhinz)
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/terminal.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 136aa0e401..d603a6a877 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -307,9 +307,12 @@ void terminal_close(Terminal *term, char *msg) term->forward_mouse = false; term->closed = true; if (!msg || exiting) { - // If no msg was given, this was called by close_buffer(buffer.c) so we - // should not wait for the user to press a key. Also cannot wait if - // `exiting == true` + // If no msg was given, this was called by close_buffer(buffer.c). Or if + // exiting, we must inform the buffer the terminal no longer exists so that + // close_buffer() doesn't call this again. + term->buf->terminal = NULL; + term->buf = NULL; + // We should not wait for the user to press a key. term->opts.close_cb(term->opts.data); } else { terminal_receive(term, msg, strlen(msg)); @@ -451,7 +454,9 @@ end: void terminal_destroy(Terminal *term) { - term->buf->terminal = NULL; + if (term->buf) { + term->buf->terminal = NULL; + } term->buf = NULL; pmap_del(ptr_t)(invalidated_terminals, term); for (size_t i = 0 ; i < term->sb_current; i++) { @@ -930,8 +935,13 @@ static void on_refresh(Event event) // be used act on terminal output. block_autocmds(); map_foreach(invalidated_terminals, term, stub, { - if (!term->buf) { + // TODO(SplinterOfChaos): Find the condition that makes term->buf invalid. + bool valid = true; + if (!term->buf || !(valid = buf_valid(term->buf))) { // destroyed by `close_buffer`. Dont do anything else + if (!valid) { + term->buf = NULL; + } continue; } bool pending_resize = term->pending_resize; |