mirror of
https://github.com/neovim/neovim.git
synced 2025-09-24 12:08:33 +00:00
terminal.c: Events in terminal_enter() should not free the terminal
It is possible for a processed event in the input loop of terminal_enter() to destroy the terminal. But this is undetected by the function and it still tries to use the freed terminal. Use a reference count to delay the freeing of the terminal until terminal_enter() returns. Fixes #3112
This commit is contained in:
@@ -132,6 +132,8 @@ struct terminal {
|
|||||||
// the default values are used to obtain the color numbers passed to cterm
|
// the default values are used to obtain the color numbers passed to cterm
|
||||||
// colors
|
// colors
|
||||||
RgbValue colors[256];
|
RgbValue colors[256];
|
||||||
|
// With a reference count of 0 the terminal can be freed.
|
||||||
|
size_t refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VTermScreenCallbacks vterm_screen_callbacks = {
|
static VTermScreenCallbacks vterm_screen_callbacks = {
|
||||||
@@ -277,8 +279,10 @@ void terminal_close(Terminal *term, char *msg)
|
|||||||
// close_buffer() doesn't call this again.
|
// close_buffer() doesn't call this again.
|
||||||
term->buf->terminal = NULL;
|
term->buf->terminal = NULL;
|
||||||
term->buf = NULL;
|
term->buf = NULL;
|
||||||
|
if (!term->refcount) {
|
||||||
// We should not wait for the user to press a key.
|
// We should not wait for the user to press a key.
|
||||||
term->opts.close_cb(term->opts.data);
|
term->opts.close_cb(term->opts.data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
terminal_receive(term, msg, strlen(msg));
|
terminal_receive(term, msg, strlen(msg));
|
||||||
}
|
}
|
||||||
@@ -376,7 +380,14 @@ void terminal_enter(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case K_EVENT:
|
case K_EVENT:
|
||||||
|
// We cannot let an event free the terminal yet. It is still needed.
|
||||||
|
term->refcount++;
|
||||||
queue_process_events(loop.events);
|
queue_process_events(loop.events);
|
||||||
|
term->refcount--;
|
||||||
|
if (term->buf == NULL) {
|
||||||
|
close = true;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Ctrl_N:
|
case Ctrl_N:
|
||||||
@@ -422,6 +433,8 @@ void terminal_destroy(Terminal *term)
|
|||||||
term->buf->terminal = NULL;
|
term->buf->terminal = NULL;
|
||||||
}
|
}
|
||||||
term->buf = NULL;
|
term->buf = NULL;
|
||||||
|
|
||||||
|
if (!term->refcount) {
|
||||||
if (pmap_has(ptr_t)(invalidated_terminals, term)) {
|
if (pmap_has(ptr_t)(invalidated_terminals, term)) {
|
||||||
// flush any pending changes to the buffer
|
// flush any pending changes to the buffer
|
||||||
block_autocmds();
|
block_autocmds();
|
||||||
@@ -436,6 +449,7 @@ void terminal_destroy(Terminal *term)
|
|||||||
vterm_free(term->vt);
|
vterm_free(term->vt);
|
||||||
xfree(term);
|
xfree(term);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void terminal_send(Terminal *term, char *data, size_t size)
|
void terminal_send(Terminal *term, char *data, size_t size)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user