aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorScott Prager <splinterofchaos@gmail.com>2015-04-06 17:47:08 -0400
committerScott Prager <splinterofchaos@gmail.com>2015-04-07 16:05:00 -0400
commit8cac2eea751379e0195b5160f9d14d19f8866e71 (patch)
tree1b59157c5f89cc8db04422d6df715cf59defde27 /src
parent013bd4461d95341fbd7c2f742844666a5e966f94 (diff)
downloadrneovim-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.c20
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;