fix(channel): crash on failed sockconnect() (#37811)

Problem:  Crash on failed sockconnect() if a new connection is accepted
          while polling for uv events.
Solution: Don't use channel_destroy_early().

Also test "tcp" mode failure properly.
This commit is contained in:
zeertzjq
2026-02-11 09:34:38 +08:00
committed by GitHub
parent 3e843a2891
commit 64ce5382bd
2 changed files with 26 additions and 2 deletions

View File

@@ -474,7 +474,9 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader
channel = channel_alloc(kChannelStreamSocket);
if (!socket_connect(&main_loop, &channel->stream.socket,
tcp, address, timeout, error)) {
channel_destroy_early(channel);
// Don't use channel_destroy_early() as new channels may have been allocated
// by channel_from_connection() while polling for uv events.
channel_decref(channel);
return 0;
}

View File

@@ -478,9 +478,31 @@ describe('channels', function()
end)
it('in "tcp" mode', function()
skip(not is_os('linux'), 'FIXME: hangs on non-Linux')
eq(
'Vim:connection failed: connection refused',
pcall_err(fn.sockconnect, 'pipe', '127.0.0.1:0')
pcall_err(fn.sockconnect, 'tcp', '127.0.0.1:0')
)
end)
it('with another connection accepted while polling #37807', function()
local server = api.nvim_get_vvar('servername')
local invalid_pipe = n.new_pipename()
exec_lua(function()
vim.defer_fn(function()
vim.uv.sleep(50) -- Block the uv event loop.
vim.fn.sockconnect('pipe', invalid_pipe)
end, 10)
end)
vim.uv.sleep(20)
-- The server uv event loop is currently blocked, so the connection will
-- be accepted when sockconnect() polls.
local other_session = n.connect(server)
eq({ true, { 1000 } }, { other_session:request('nvim_list_wins') })
other_session:close()
matches(
'^vim.schedule callback: Vim:connection failed: connection refused\n',
api.nvim_get_vvar('errmsg')
)
end)
end)