Mercurial > vim
diff src/channel.c @ 8055:6db4b1c863ec v7.4.1322
commit https://github.com/vim/vim/commit/3bece9fee9c02934d3e295b29d253e13d4ef26a7
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Feb 15 20:39:46 2016 +0100
patch 7.4.1322
Problem: Crash when unletting the variable that holds the channel in a
callback function. (Christian Robinson)
Solution: Increase the reference count while invoking the callback.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 15 Feb 2016 20:45:04 +0100 |
parents | 15253130abd8 |
children | 19304db153bc |
line wrap: on
line diff
--- a/src/channel.c +++ b/src/channel.c @@ -1217,8 +1217,6 @@ channel_close(channel_T *channel) #endif channel->ch_close_cb = NULL; - vim_free(channel->ch_callback); - channel->ch_callback = NULL; channel_clear(channel); } @@ -1298,6 +1296,9 @@ channel_clear(channel_T *channel) free_tv(json_head->jq_next->jq_value); remove_json_node(json_head, json_head->jq_next); } + + vim_free(channel->ch_callback); + channel->ch_callback = NULL; } #if defined(EXITFREE) || defined(PROTO) @@ -1802,15 +1803,28 @@ channel_select_check(int ret_in, void *r int channel_parse_messages(void) { - channel_T *channel; - int ret = FALSE; + channel_T *channel = first_channel; + int ret = FALSE; + int r; - for (channel = first_channel; channel != NULL; channel = channel->ch_next) - while (may_invoke_callback(channel) == OK) + while (channel != NULL) + { + /* Increase the refcount, in case the handler causes the channel to be + * unreferenced or closed. */ + ++channel->ch_refcount; + r = may_invoke_callback(channel); + if (channel_unref(channel)) + /* channel was freed, start over */ + channel = first_channel; + + if (r == OK) { - channel = first_channel; /* start over */ + channel = first_channel; /* something was done, start over */ ret = TRUE; } + else + channel = channel->ch_next; + } return ret; }