Mercurial > vim
changeset 28612:352806724e12 v8.2.4830
patch 8.2.4830: possible endless loop if there is unused typahead
Commit: https://github.com/vim/vim/commit/23f106efeb64eadd95adee34144f64526aa5f61f
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Apr 26 18:52:22 2022 +0100
patch 8.2.4830: possible endless loop if there is unused typahead
Problem: Possible endless loop if there is unused typahead.
Solution: Only loop when the typeahead changed.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 26 Apr 2022 20:00:04 +0200 |
parents | ab50b921aea6 |
children | a56f5442fd9a |
files | src/channel.c src/version.c |
diffstat | 2 files changed, 38 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/channel.c +++ b/src/channel.c @@ -2029,7 +2029,7 @@ channel_consume(channel_T *channel, ch_p /* * Collapses the first and second buffer for "channel"/"part". - * Returns FAIL if that is not possible. + * Returns FAIL if nothing was done. * When "want_nl" is TRUE collapse more buffers until a NL is found. * When the channel part mode is "lsp", collapse all the buffers as the http * header and the JSON content can be present in multiple buffers. @@ -2957,6 +2957,17 @@ drop_messages(channel_T *channel, ch_par } /* + * Return TRUE if for "channel" / "part" ch_json_head should be used. + */ + static int +channel_use_json_head(channel_T *channel, ch_part_T part) +{ + ch_mode_T ch_mode = channel->ch_part[part].ch_mode; + + return ch_mode == MODE_JSON || ch_mode == MODE_JS || ch_mode == MODE_LSP; +} + +/* * Invoke a callback for "channel"/"part" if needed. * This does not redraw but sets channel_need_redraw when redraw is needed. * Return TRUE when a message was handled, there might be another one. @@ -3002,7 +3013,7 @@ may_invoke_callback(channel_T *channel, buffer = NULL; } - if (ch_mode == MODE_JSON || ch_mode == MODE_JS || ch_mode == MODE_LSP) + if (channel_use_json_head(channel, part)) { listitem_T *item; int argc = 0; @@ -3248,14 +3259,13 @@ channel_is_open(channel_T *channel) } /* - * Return TRUE if "channel" has JSON or other typeahead. + * Return a pointer indicating the readahead. Can only be compared between + * calls. Returns NULL if there is no readahead. */ - static int -channel_has_readahead(channel_T *channel, ch_part_T part) + static void * +channel_readahead_pointer(channel_T *channel, ch_part_T part) { - ch_mode_T ch_mode = channel->ch_part[part].ch_mode; - - if (ch_mode == MODE_JSON || ch_mode == MODE_JS || ch_mode == MODE_LSP) + if (channel_use_json_head(channel, part)) { jsonq_T *head = &channel->ch_part[part].ch_json_head; @@ -3264,9 +3274,18 @@ channel_has_readahead(channel_T *channel // process. channel_parse_json(channel, part); - return head->jq_next != NULL; + return head->jq_next; } - return channel_peek(channel, part) != NULL; + return channel_peek(channel, part); +} + +/* + * Return TRUE if "channel" has JSON or other typeahead. + */ + static int +channel_has_readahead(channel_T *channel, ch_part_T part) +{ + return channel_readahead_pointer(channel, part) != NULL; } /* @@ -4013,14 +4032,19 @@ channel_read_json_block( if (!more) { + void *prev_readahead_ptr = channel_readahead_pointer(channel, part); + void *readahead_ptr; + // Handle any other messages in the queue. If done some more // messages may have arrived. if (channel_parse_messages()) continue; // channel_parse_messages() may fill the queue with new data to - // process. - if (channel_has_readahead(channel, part)) + // process. Only loop when the readahead changed, otherwise we + // would busy-loop. + readahead_ptr = channel_readahead_pointer(channel, part); + if (readahead_ptr != NULL && readahead_ptr != prev_readahead_ptr) continue; // Wait for up to the timeout. If there was an incomplete message