From 3237c9e0e2e4419c093315c69a3d07802663aa7a Mon Sep 17 00:00:00 2001 From: kay Date: Fri, 28 Aug 2026 19:38:24 +0900 Subject: [PATCH] Fixed underline and half-bright being discarded where plain char is unsigned s8 is a typedef for plain char, whose signedness is implementation-defined. The Arm procedure call standard maps char to "unsigned byte" (AAPCS32 section 8.1.1, "LDRB is unsigned"), so the -1 sentinel stored in cur_underline_color and cur_halfbright_color reads back as 255 there and the guards in normal_char_attr() are true unconditionally: if (a.underline && cur_underline_color != -1) { // 255 != -1 a.underline = false; a.fcolor = cur_underline_color; // fg forced to 255 } Underline (SGR 4) is therefore dropped and the cell is drawn with color index 255, a near-white gray on the default palette, so the failure is easy to overlook: the text looks almost normal, it just loses the decoration. The half-bright branch below it has the same defect and replaces the intended gray with color 255. The guards predate the decoration rendering added in ccf83cf; before that commit fbterm never drew underlines, so the bug had no observable effect. The typedef itself cannot be changed to signed char, because s8 is also the string type used throughout the tree and signed char * is not assignable from a string literal in C++. -fsigned-char would work too, but it also changes the interpretation of every s8 buffer holding UTF-8 bytes, so widening the two fields seemed the smaller change. They only ever hold -1 to 7. Verified on armv7l (Debian 12). Co-Authored-By: Claude Opus 5 (1M context) --- src/lib/vterm.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/vterm.h b/src/lib/vterm.h index 08b3723..f76bf81 100644 --- a/src/lib/vterm.h +++ b/src/lib/vterm.h @@ -357,7 +357,11 @@ class VTerm { static CharAttr default_char_attr; u8 cur_fcolor, cur_bcolor; - s8 cur_underline_color, cur_halfbright_color; + // Not s8: that typedef resolves to plain char, whose signedness is + // implementation-defined. On targets where char is unsigned (ARM, + // AArch64, PowerPC, s390x) the -1 sentinel below reads back as 255 and + // every `!= -1` guard in normal_char_attr() fires unconditionally. + s16 cur_underline_color, cur_halfbright_color; ScreenBufferType active_buffer = Primary; // action parameters