mirror of
https://github.com/neovim/neovim.git
synced 2025-09-26 13:08:33 +00:00
msgpack-rpc: Ensure stdio channels are properly closed
When stdio was closed, parse_msgpack was called with eof == true, with caused a free_channel call. To ensure the correct behavior for all types of channels, the close_channel must be called before free_channel.
This commit is contained in:
@@ -225,6 +225,10 @@ Object channel_send_call(uint64_t id,
|
|||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channel->closed && !kv_size(channel->call_stack)) {
|
||||||
|
free_channel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
return frame.result;
|
return frame.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +332,7 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
|
|||||||
Channel *channel = data;
|
Channel *channel = data;
|
||||||
|
|
||||||
if (eof) {
|
if (eof) {
|
||||||
goto end;
|
close_channel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t count = rstream_pending(rstream);
|
size_t count = rstream_pending(rstream);
|
||||||
@@ -363,7 +367,7 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
|
|||||||
}
|
}
|
||||||
msgpack_unpacked_destroy(&unpacked);
|
msgpack_unpacked_destroy(&unpacked);
|
||||||
// Bail out from this event loop iteration
|
// Bail out from this event loop iteration
|
||||||
goto end;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_request(channel, &unpacked.data);
|
handle_request(channel, &unpacked.data);
|
||||||
@@ -386,14 +390,6 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof)
|
|||||||
"This error can also happen when deserializing "
|
"This error can also happen when deserializing "
|
||||||
"an object with high level of nesting");
|
"an object with high level of nesting");
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
|
||||||
if (eof && !channel->is_job && !kv_size(channel->call_stack)) {
|
|
||||||
// The free_channel call is deferred for jobs because it's possible that
|
|
||||||
// job_stderr will called after this. For non-job channels, this is the
|
|
||||||
// last callback so it must be freed now.
|
|
||||||
free_channel(channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_request(Channel *channel, msgpack_object *request)
|
static void handle_request(Channel *channel, msgpack_object *request)
|
||||||
@@ -569,6 +565,10 @@ static void unsubscribe(Channel *channel, char *event)
|
|||||||
/// free_channel later.
|
/// free_channel later.
|
||||||
static void close_channel(Channel *channel)
|
static void close_channel(Channel *channel)
|
||||||
{
|
{
|
||||||
|
if (channel->closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
channel->closed = true;
|
channel->closed = true;
|
||||||
if (channel->is_job) {
|
if (channel->is_job) {
|
||||||
if (channel->data.job) {
|
if (channel->data.job) {
|
||||||
@@ -577,10 +577,10 @@ static void close_channel(Channel *channel)
|
|||||||
} else {
|
} else {
|
||||||
rstream_free(channel->data.streams.read);
|
rstream_free(channel->data.streams.read);
|
||||||
wstream_free(channel->data.streams.write);
|
wstream_free(channel->data.streams.write);
|
||||||
if (channel->data.streams.uv) {
|
uv_handle_t *handle = (uv_handle_t *)channel->data.streams.uv;
|
||||||
uv_close((uv_handle_t *)channel->data.streams.uv, close_cb);
|
if (handle) {
|
||||||
|
uv_close(handle, close_cb);
|
||||||
} else {
|
} else {
|
||||||
// When the stdin channel closes, it's time to go
|
|
||||||
mch_exit(0);
|
mch_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user