From 23f106efeb64eadd95adee34144f64526aa5f61f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 26 Apr 2022 18:52:22 +0100 Subject: [PATCH] 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. --- src/channel.c | 48 ++++++++++++++++++++++++++++++++++++------------ src/version.c | 2 ++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/channel.c b/src/channel.c index 87dc00cd0..d6782e918 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2029,7 +2029,7 @@ channel_consume(channel_T *channel, ch_part_T part, int len) /* * 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. @@ -2956,6 +2956,17 @@ drop_messages(channel_T *channel, ch_part_T part) } } +/* + * 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. @@ -3002,7 +3013,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part) 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, ch_part_T part) // 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 diff --git a/src/version.c b/src/version.c index 54f350bf8..1c799d89e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4830, /**/ 4829, /**/ -- 2.40.0