diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-03-19 16:56:51 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-19 16:56:51 +0800 |
commit | 16a416cb3c17ed3a7f21d35da5d211fcad947768 (patch) | |
tree | 55372aaea468fb1289fdfbc38a7eb780af7fbb12 /src | |
parent | c30ebb17f6b98625e3db8f032c2223876bb60f99 (diff) | |
download | rneovim-16a416cb3c17ed3a7f21d35da5d211fcad947768.tar.gz rneovim-16a416cb3c17ed3a7f21d35da5d211fcad947768.tar.bz2 rneovim-16a416cb3c17ed3a7f21d35da5d211fcad947768.zip |
fix(terminal): don't pass incomplete UTF-8 sequence to libvterm (#27922)
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/channel.c | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c index ebeaffe5a1..0222a134a7 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -29,6 +29,7 @@ #include "nvim/log.h" #include "nvim/lua/executor.h" #include "nvim/main.h" +#include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" @@ -646,35 +647,52 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, count, eof, &chan->on_data); + on_channel_output(stream, chan, buf, eof, &chan->on_data); } void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr); + on_channel_output(stream, chan, buf, eof, &chan->on_stderr); } -static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, size_t count, bool eof, +static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof, CallbackReader *reader) { - // stub variable, to keep reading consistent with the order of events, only - // consider the count parameter. - size_t r; - char *ptr = rbuffer_read_ptr(buf, &r); + size_t count; + char *output = rbuffer_read_ptr(buf, &count); - if (eof) { - reader->eof = true; - } else { - if (chan->term) { - terminal_receive(chan->term, ptr, count); + if (chan->term) { + if (!eof) { + char *p = output; + char *end = output + count; + while (p < end) { + // Don't pass incomplete UTF-8 sequences to libvterm. #16245 + // Composing chars can be passed separately, so utf_ptr2len_len() is enough. + int clen = utf_ptr2len_len(p, (int)(end - p)); + if (clen > end - p) { + count = (size_t)(p - output); + break; + } + p += clen; + } } + terminal_receive(chan->term, output, count); + } + + if (count) { rbuffer_consumed(buf, count); + } + // Move remaining data to start of buffer, so the buffer can never wrap around. + rbuffer_reset(buf); - if (callback_reader_set(*reader)) { - ga_concat_len(&reader->buffer, ptr, count); - } + if (callback_reader_set(*reader)) { + ga_concat_len(&reader->buffer, output, count); + } + + if (eof) { + reader->eof = true; } if (callback_reader_set(*reader)) { |