aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-03-19 16:56:51 +0800
committerGitHub <noreply@github.com>2024-03-19 16:56:51 +0800
commit16a416cb3c17ed3a7f21d35da5d211fcad947768 (patch)
tree55372aaea468fb1289fdfbc38a7eb780af7fbb12 /src
parentc30ebb17f6b98625e3db8f032c2223876bb60f99 (diff)
downloadrneovim-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.c48
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)) {