mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 04:42:03 +00:00
fix(tui): heap-use-after-free when resuming (#36387)
Discovered when writing more tests for suspend/resume. It seems that this isn't always reproducible with ASAN due to the arena.
This commit is contained in:
@@ -368,6 +368,7 @@ static void terminfo_start(TUIData *tui)
|
||||
tui->input.tui_data = tui;
|
||||
|
||||
tui->ti_arena = (Arena)ARENA_EMPTY;
|
||||
assert(tui->term == NULL);
|
||||
|
||||
char *term = os_getenv("TERM");
|
||||
#ifdef MSWIN
|
||||
@@ -384,9 +385,7 @@ static void terminfo_start(TUIData *tui)
|
||||
bool found_in_db = false;
|
||||
if (term) {
|
||||
if (terminfo_from_unibilium(&tui->ti, term, &tui->ti_arena)) {
|
||||
if (!tui->term) {
|
||||
tui->term = arena_strdup(&tui->ti_arena, term);
|
||||
}
|
||||
tui->term = arena_strdup(&tui->ti_arena, term);
|
||||
found_in_db = true;
|
||||
}
|
||||
}
|
||||
@@ -590,6 +589,9 @@ static void terminfo_stop(TUIData *tui)
|
||||
abort();
|
||||
}
|
||||
arena_mem_free(arena_finish(&tui->ti_arena));
|
||||
// Avoid using freed memory.
|
||||
memset(&tui->ti, 0, sizeof(tui->ti));
|
||||
tui->term = NULL;
|
||||
}
|
||||
|
||||
static void tui_terminal_start(TUIData *tui)
|
||||
|
||||
@@ -4141,4 +4141,69 @@ describe('TUI client', function()
|
||||
test_remote_tui_quit(42)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('suspend/resume works with multiple clients', function()
|
||||
local server_super, screen_server, screen_client = start_tui_and_remote_client()
|
||||
local server_super_exec_lua = tt.make_lua_executor(server_super)
|
||||
|
||||
local screen_normal = [[
|
||||
Hello, Worl^d |
|
||||
{100:~ }|*3
|
||||
{3:[No Name] [+] }|
|
||||
|
|
||||
{5:-- TERMINAL --} |
|
||||
]]
|
||||
local screen_suspended = [[
|
||||
^ |
|
||||
|*5
|
||||
{5:-- TERMINAL --} |
|
||||
]]
|
||||
|
||||
screen_client:expect({ grid = screen_normal, unchanged = true })
|
||||
screen_server:expect({ grid = screen_normal, unchanged = true })
|
||||
|
||||
-- Suspend both clients.
|
||||
feed_data(':suspend\r')
|
||||
screen_client:expect({ grid = screen_suspended })
|
||||
screen_server:expect({ grid = screen_suspended })
|
||||
|
||||
-- Resume the remote client.
|
||||
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigcont')]])
|
||||
screen_client:expect({ grid = screen_normal })
|
||||
screen_server:expect({ grid = screen_suspended, unchanged = true })
|
||||
|
||||
-- Resume the embedding client.
|
||||
server_super_exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigcont')]])
|
||||
screen_server:expect({ grid = screen_normal })
|
||||
screen_client:expect({ grid = screen_normal, unchanged = true })
|
||||
|
||||
-- Suspend both clients again.
|
||||
feed_data(':suspend\r')
|
||||
screen_client:expect({ grid = screen_suspended })
|
||||
screen_server:expect({ grid = screen_suspended })
|
||||
|
||||
-- Resume the remote client.
|
||||
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigcont')]])
|
||||
screen_client:expect({ grid = screen_normal })
|
||||
screen_server:expect({ grid = screen_suspended, unchanged = true })
|
||||
|
||||
-- Suspend the remote client again.
|
||||
feed_data(':suspend\r')
|
||||
screen_client:expect({ grid = screen_suspended })
|
||||
screen_server:expect({ grid = screen_suspended, unchanged = true })
|
||||
|
||||
-- Resume the embedding client.
|
||||
server_super_exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigcont')]])
|
||||
screen_server:expect({ grid = screen_normal })
|
||||
screen_client:expect({ grid = screen_suspended, unchanged = true })
|
||||
|
||||
-- Resume the remote client.
|
||||
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigcont')]])
|
||||
screen_client:expect({ grid = screen_normal })
|
||||
screen_server:expect({ grid = screen_normal, unchanged = true })
|
||||
|
||||
feed_data(':quit!\r')
|
||||
screen_server:expect({ any = vim.pesc('[Process exited 0]') })
|
||||
screen_client:expect({ any = vim.pesc('[Process exited 0]') })
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user