channel.c: Only free a channel after close callbacks are executed #3132

parse_msgpack() closes a channel's stream on EOF error and the stream's
close callback close_cb() is queued for the next libuv loop iteration.
When parse_msgpack() returns, it has freed the channel and the queued
stream callback will access this freed memory.

To prevent this, increase the channel's reference count and let the
stream's close callback call decref().

Fixes #3128
This commit is contained in:
oni-link 2015-08-05 07:54:44 +02:00 committed by Justin M. Keyes
parent 2e1a80563b
commit b732a27c4e

View File

@ -153,6 +153,9 @@ void channel_from_connection(SocketWatcher *watcher)
{
Channel *channel = register_channel(kChannelTypeSocket);
socket_watcher_accept(watcher, &channel->data.stream, channel);
incref(channel); // close channel only after the stream is closed
channel->data.stream.internal_close_cb = close_cb;
channel->data.stream.internal_data = channel;
wstream_init(&channel->data.stream, 0);
rstream_init(&channel->data.stream, CHANNEL_BUFFER_SIZE);
rstream_start(&channel->data.stream, parse_msgpack);
@ -636,7 +639,7 @@ static void close_channel(Channel *channel)
switch (channel->type) {
case kChannelTypeSocket:
stream_close(&channel->data.stream, close_cb);
stream_close(&channel->data.stream, NULL);
break;
case kChannelTypeProc:
if (!channel->data.process.uvproc.process.closed) {
@ -685,7 +688,7 @@ static void free_channel(Channel *channel)
static void close_cb(Stream *stream, void *data)
{
xfree(data);
decref(data);
}
static Channel *register_channel(ChannelType type)