aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2018-01-07 10:16:39 +0100
committerBjörn Linse <bjorn.linse@gmail.com>2018-04-12 18:22:47 +0200
commitaea079a25df1df5c94e97adf3c92ead397168e27 (patch)
tree074dd870dc27ec4a598b7d317a6bad3c9e7ceea9
parent2cbeb7ca56503ebc203a7fae469d3ede9a5d80da (diff)
downloadrneovim-aea079a25df1df5c94e97adf3c92ead397168e27.tar.gz
rneovim-aea079a25df1df5c94e97adf3c92ead397168e27.tar.bz2
rneovim-aea079a25df1df5c94e97adf3c92ead397168e27.zip
channels: delay free so that libuv can cleanup handles
add test for a crash this caused
-rw-r--r--src/nvim/channel.c8
-rw-r--r--test/functional/core/job_spec.lua15
2 files changed, 21 insertions, 2 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 2e32af2e9a..f31ba424f5 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -245,7 +245,8 @@ void channel_incref(Channel *channel)
void channel_decref(Channel *channel)
{
if (!(--channel->refcount)) {
- multiqueue_put(main_loop.fast_events, free_channel_event, 1, channel);
+ // delay free, so that libuv is done with the handles
+ multiqueue_put(main_loop.events, free_channel_event, 1, channel);
}
}
@@ -286,12 +287,15 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
+ pmap_del(uint64_t)(channels, chan->id);
+ chan->id = 0;
if ((--chan->refcount != 0)) {
abort();
}
- free_channel_event((void **)&chan);
+ // uv will keep a reference to handles until next loop tick, so delay free
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 6d4cadbdc8..24bff423df 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -640,6 +640,21 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set") ~= nil)
end)
+ it('does not crash when repeatedly failing to start shell', function()
+ source([[
+ set shell=nosuchshell
+ func! DoIt()
+ call jobstart('true')
+ call jobstart('true')
+ endfunc
+ ]])
+ -- The crash only triggered if both jobs are cleaned up on the same event
+ -- loop tick. This is also prevented by try-block, so feed must be used.
+ feed_command("call DoIt()")
+ feed('<cr>') -- press RETURN
+ eq(2,eval('1+1'))
+ end)
+
it('jobstop() kills entire process tree #6530', function()
command('set shell& shellcmdflag& shellquote& shellpipe& shellredir& shellxquote&')