neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 64ce5382bd53de0500d9bcfba4e8d2a7f3421af6
parent 3e843a2891258c1a297daa97e9704d9bf110b760
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Wed, 11 Feb 2026 09:34:38 +0800

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.
Diffstat:
Msrc/nvim/channel.c | 4+++-
Mtest/functional/core/channels_spec.lua | 24+++++++++++++++++++++++-
2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/src/nvim/channel.c b/src/nvim/channel.c @@ -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; } diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua @@ -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)