git: 705a88a71727 - main - ee: Improve handling of malformed UTF-8 characters

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 06 Jul 2026 13:18:51 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=705a88a717272c52c897c3d28dc2997980ee67f4

commit 705a88a717272c52c897c3d28dc2997980ee67f4
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-07-06 13:16:32 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-07-06 13:18:13 +0000

    ee: Improve handling of malformed UTF-8 characters
    
    In delete(), when copying the deleted character to the d_char buffer,
    don't assume that it fits.  utf8_prev() may return a sequence of more
    than 5 bytes.
    
    In insert_utf8(), fix the copy-up of the line.  We extended the line by
    "len" bytes, so "temp" has to be repositioned accordingly.  Compare with
    plain insert().
    
    Use sizeof when copying to buffers instead of hard-coding buffer sizes.
    
    Don't dynamically allocate d_char, there is no need.
    
    Fixes:          62fba0054d9e ("ee: add unicode support")
    Reported by:    Sayono Hiragi (overflow in delete())
    Reviewed by:    bapt
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57996
---
 contrib/ee/ee.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/contrib/ee/ee.c b/contrib/ee/ee.c
index 13a554bf0146..94bb296bcd65 100644
--- a/contrib/ee/ee.c
+++ b/contrib/ee/ee.c
@@ -194,7 +194,7 @@ unsigned char *srch_2;		/* pointer to next character of string	*/
 unsigned char *srch_3;
 unsigned char *in_file_name = NULL;	/* name of input file		*/
 char *tmp_file;	/* temporary file name			*/
-unsigned char *d_char;		/* deleted character			*/
+unsigned char d_char[5];	/* deleted character			*/
 unsigned char *d_word;		/* deleted word				*/
 unsigned char *d_line;		/* deleted line				*/
 char in_string[513];	/* buffer for reading a file		*/
@@ -598,7 +598,6 @@ main(int argc, char *argv[])
 	signal(SIGCHLD, SIG_DFL);
 	signal(SIGSEGV, SIG_DFL);
 	signal(SIGINT, edit_abort);
-	d_char = malloc(5);	/* UTF-8 chars can be up to 4 bytes + NUL */
 	d_word = malloc(150);
 	*d_word = '\0';
 	d_line = NULL;
@@ -832,7 +831,6 @@ insert_utf8(const unsigned char *mb, int len)
 {
 	int counter;
 	unsigned char *temp;
-	unsigned char *temp2;
 	int i;
 
 	text_changes = TRUE;
@@ -848,17 +846,18 @@ insert_utf8(const unsigned char *mb, int len)
 		counter++;
 		temp++;
 	}
-	temp++;
-	while (point < temp)
+	temp += len;
+	while (point + len - 1 < temp)
 	{
+		unsigned char *temp2;
+
 		temp2 = temp - len;
 		*temp = *temp2;
 		temp--;
 	}
 
 	/* copy all bytes of the UTF-8 character */
-	for (i = 0; i < len; i++)
-		point[i] = mb[i];
+	memmove(point, mb, len);
 
 	/* display the character before advancing past it */
 	wclrtoeol(text_win);
@@ -931,8 +930,10 @@ delete(int disp)
 		scr_pos = scr_horz;
 		if (in == 8)
 		{
-			memcpy(d_char, point, del_width);
-			d_char[del_width] = '\0';
+			size_t width = min(del_width, 4);
+
+			memcpy(d_char, point, width);
+			d_char[width] = '\0';
 		}
 		while (temp_pos <= curr_line->line_length)
 		{
@@ -2993,7 +2994,7 @@ del_word(void)
 	if (d_word != NULL)
 		free(d_word);
 	d_word = malloc(curr_line->line_length);
-	memcpy(tmp_char, d_char, 5);
+	memcpy(tmp_char, d_char, sizeof(tmp_char));
 	d_word3 = point;
 	d_word2 = d_word;
 	tposit = position;
@@ -3026,7 +3027,7 @@ del_word(void)
 	curr_line->line_length -= difference;
 	*d_word2 = '\0';
 	draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
-	memcpy(d_char, tmp_char, 5);
+	memcpy(d_char, tmp_char, sizeof(d_char));
 	text_changes = TRUE;
 	formatted = FALSE;
 }
@@ -4141,7 +4142,7 @@ Format(void)
 	unsigned char *temp_dword;
 	unsigned char temp_d_char[5];
 
-	memcpy(temp_d_char, d_char, 5);
+	memcpy(temp_d_char, d_char, sizeof(temp_d_char));
 
 /*
  |	if observ_margins is not set, or the current line is blank,
@@ -4336,7 +4337,7 @@ Format(void)
 	case_sen = temp_case;
 	free(srch_str);
 	srch_str = tmp_srchstr;
-	memcpy(d_char, temp_d_char, 5);
+	memcpy(d_char, temp_d_char, sizeof(d_char));
 	auto_format = tmp_af;
 
 	midscreen(scr_vert, point);
@@ -4720,7 +4721,7 @@ Auto_Format(void)
 	unsigned char temp_d_char[5];
 	unsigned char *tmp_d_line;
 
-	memcpy(temp_d_char, d_char, 5);
+	memcpy(temp_d_char, d_char, sizeof(temp_d_char));
 
 /*
  |	if observ_margins is not set, or the current line is blank, 
@@ -4946,7 +4947,7 @@ Auto_Format(void)
 	case_sen = temp_case;
 	free(srch_str);
 	srch_str = tmp_srchstr;
-	memcpy(d_char, temp_d_char, 5);
+	memcpy(d_char, temp_d_char, sizeof(d_char));
 	auto_format = TRUE;
 	dlt_line->line_length = tmp_d_line_length;
 	d_line = tmp_d_line;