Subject: bug#76517: 31.0.50; feature/igc 6ff509af3d31 crash on Wayland KDE, (with -g3

From: Pip Cet <[email-masked]>
Date: Mon, 24 Feb 2025 21:01:31 +0000

Pip Cet <[email-masked]> writes:

> "Eli Zaretskii" <[email-masked]> writes:
>
>>> Cc: [email-masked]
>>> Date: Mon, 24 Feb 2025 15:49:38 +0000
>>> From:  Pip Cet via "Bug reports for GNU Emacs,
>>>  the Swiss army knife of text editors" <[email-masked]>
>>>
>>> "Eval Exec" <[email-masked]> writes:
>>>
>>> > Hello,
>>> > I'm helping to test feature/igc branch
>>>
>>> Thanks for the report!
>>>
>>> At first glance, the problem doesn't seem to be specific to feature/igc.
>>>
>>> > #16 0x00000000004933d8 in c_string_width (nbytes=<synthetic pointer>,
>>> > nchars=<synthetic pointer>, precision=<optimized out>, len=69,
>>> >     str=0x7f1ec16860fa "\274\214我中间使用 充电宝给电脑冲了一次电。还行。。。") at
>>>
>>> This string starts with an incomplete character sequence.
>>
>> The evaluation of the header-line-format shows the complete string.
>
> The relevant part in the screenshot is "%，我中间使用"
>
>>> As the screenshot at https://imgur.com/a/tON6P7w (why a screenshot?)
>>> shows, the last character before that is "%", followed by what looks
>>> like "，", a fullwidth comma.
>>>
>>> It seems the "%" was interpreted as introducing a mode line escape,
>>> which used the first byte of the three-byte encoding used for the
>>> fullwidth comma.  The remaining bytes were then interpreted as the
>>> beginning of a multi-byte character, which ended up out of range and
>>> accessing an element of the display_table_ chartab which wasn't defined.
>>>
>>> So I guess our mode line escapes need to be fixed for multibyte
>>> characters, and hopefully no further action is necessary (you might also
>>> want to consider not making mode line escapes part of your header
>>> lines).
>>
>> I don't see any "%", but are you saying that some UTF-8 byte sequence
>
> Look at the screenshot.
>
>> of a non-ASCII character that is not the character '%' itself could
>> have the '%' byte as part of it?  I thought that was impossible,
>
> No.  I'm saying that display_mode_element scans for a '%', finds it,
> takes the next byte, which is the first byte of the fullwidth comma,,
> passes it to decode_mode_spec, then leaves offset pointing to the second
> byte of the multi-byte sequence following the %, and attempts to
> continue printing the modeline from that offset, in the middle of a
> multi-byte sequence.

Maybe this proposed patch will make things clearer.  Please let me know
whether it's okay for master or how to improve it.  Thanks!

>From 550fdd160ac83a075f230a9f837ef03d64cfafce Mon Sep 17 00:00:00 2001
From: Pip Cet <[email-masked]>
Subject: [PATCH] Handle multibyte mode line spec chars (bug#76517)

A percentage sign followed by a non-ASCII character could previously
result in a crash.  Ignoring such constructs makes them harmless.

* src/xdisp.c (display_mode_element): Make 'c' an 'int'.  Use
'string_char_and_length' to fetch the character from a multibyte
string, not 'SREF'.
---
 src/xdisp.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/xdisp.c b/src/xdisp.c
index 577d5b1b401..f6c74b5c9a9 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -27762,7 +27762,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
     case Lisp_String:
       {
 	/* A string: output it and check for %-constructs within it.  */
-	unsigned char c;
+	int c;
 	ptrdiff_t offset = 0;
 
 	if (SCHARS (elt) > 0
@@ -27933,6 +27933,12 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
 		while ((c = SREF (elt, offset++)) >= '0' && c <= '9')
 		  field = field * 10 + c - '0';
 
+		offset--;
+		int length = 1;
+		if (STRING_MULTIBYTE (elt))
+		  c = string_char_and_length (SDATA (elt) + offset, &length);
+		offset += length;
+
 		/* Don't pad beyond the total padding allowed.  */
 		if (field_width - n > 0 && field > field_width - n)
 		  field = field_width - n;
-- 
2.48.1

Pip