From febdf638962d981c278dd831c9eb2947da77672d Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Tue, 15 Sep 2026 20:22:06 -0400 Subject: [PATCH] Fix invalid UTF-8 byte $E2 at the end of a symbol name reading past the string's end (#2092) This is only possible in an invalid object file, but we do have other safety checks for those. Assisted-by: opencode:big-pickle --- src/link/output.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/link/output.cpp b/src/link/output.cpp index 4eb60ef6..41d9dc7c 100644 --- a/src/link/output.cpp +++ b/src/link/output.cpp @@ -267,30 +267,27 @@ static void writeROM() { } static void writeSymName(std::string const &name, FILE *file) { - for (char const *ptr = name.c_str(); *ptr != '\0';) { + for (size_t i = 0; i < name.length();) { // Output legal ASCII characters as-is - if (char c = *ptr; continuesIdentifier(c)) { + if (char c = name[i]; continuesIdentifier(c)) { putc(c, file); - ++ptr; + ++i; continue; } // Output illegal characters using Unicode escapes ('\u' or '\U') // Decode the UTF-8 codepoint; or at least attempt to Utf8Decoder decoder; - do { - if (decoder.update(*ptr++) != UTF8_REJECT) { - continue; + while (i < name.length()) { + decoder.update(static_cast(name[i++])); + if (decoder.state == UTF8_ACCEPT || decoder.state == UTF8_REJECT) { + break; } - // This sequence was invalid; emit a U+FFFD, and recover + } + if (decoder.state != UTF8_ACCEPT) { + // This sequence was invalid or incomplete; emit a U+FFFD instead decoder.codepoint = 0xFFFD; - // Skip continuation bytes - // A NUL byte does not qualify, so we're good - while ((*ptr & 0xC0) == 0x80) { - ++ptr; - } - break; - } while (decoder.state != UTF8_ACCEPT); + } fprintf( file, decoder.codepoint <= 0xFFFF ? "\\u%04" PRIx32 : "\\U%08" PRIx32, decoder.codepoint );