diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 9478ab6d68..aa0d067927 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -167,7 +167,13 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) chan->stream.err.closed = true; // Don't close on exit, in case late error messages if (!exiting) { - fclose(stderr); + // Don't close the file descriptor, as that may cause later writes to stderr + // to go to an unrelated file. Redirect it to NUL or /dev/null instead. +#ifdef MSWIN + freopen("NUL:", "w", stderr); +#else + freopen("/dev/null", "w", stderr); +#endif } channel_decref(chan); } diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 682649603e..3500cd2919 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -119,12 +119,12 @@ describe(':cquit', function() end) end) -describe('no crash after :quit non-last window during exit', function() +describe('when piping to stdin, no crash during exit', function() before_each(function() n.clear() end) - it('in vim.schedule() callback and when piping to stdin #14379', function() + it('after :quit non-last window in vim.schedule() callback #14379', function() n.fn.system({ n.nvim_prog, '-es', @@ -135,7 +135,7 @@ describe('no crash after :quit non-last window during exit', function() eq(0, n.api.nvim_get_vvar('shell_error')) end) - it('in vim.defer_fn() callback and when piping to stdin #14379', function() + it('after :quit non-last window in vim.defer_fn() callback #14379', function() n.fn.system({ n.nvim_prog, '-es', @@ -145,4 +145,15 @@ describe('no crash after :quit non-last window during exit', function() }, '') eq(0, n.api.nvim_get_vvar('shell_error')) end) + + it('after closing v:stderr channel', function() + n.fn.system({ + n.nvim_prog, + '-es', + '--cmd', + 'call chanclose(v:stderr)', + '+quit', + }, '') + eq(0, n.api.nvim_get_vvar('shell_error')) + end) end)