The application crashes with SIGABRT when terminal input contains mouse escape sequences (e.g. moving the mouse in a terminal that has mouse reporting enabled). The panic originates from std.unicode.utf8Decode in the standard library, triggered by event/input.zig passing a 32-byte slice where only a 1–4 byte slice is valid.
Zig Version: 0.15.2
OS: linux
Reproduce: Run any TUI app, move the mouse in the terminal > process aborts.
Cause: In src/event/input.zig, parseUtf8Char() receives the full stdin read buffer (e.g. 32 bytes). It calls std.unicode.utf8Decode(bytes), but Zig’s utf8Decode only accepts a slice of length 1–4 (one codepoint).
For any other length it hits else => unreachable and aborts.
Fix: Decode only the first codepoint: use utf8ByteSequenceLength(bytes[0]) to get seq_len, then call utf8Decode(bytes[0..seq_len]). On error or truncated input, return an unknown key event.
fn parseUtf8Char(self: *InputReader, bytes: []const u8) ?Event {
_ = self;
if (bytes.len == 0) return null;
// utf8Decode() only accepts a slice of exactly 1, 2, 3, or 4 bytes (one codepoint).
// Passing a longer slice (e.g. 32 bytes from stdin) hits unreachable and aborts.
const seq_len = std.unicode.utf8ByteSequenceLength(bytes[0]) catch {
return Event{ .key = .{ .key = .{ .unknown = bytes[0] } } };
};
if (bytes.len < seq_len) {
return Event{ .key = .{ .key = .{ .unknown = bytes[0] } } };
}
const cp = std.unicode.utf8Decode(bytes[0..seq_len]) catch {
return Event{ .key = .{ .key = .{ .unknown = bytes[0] } } };
};
return Event{
.key = .{ .key = .{ .char = cp } },
};
}
The application crashes with SIGABRT when terminal input contains mouse escape sequences (e.g. moving the mouse in a terminal that has mouse reporting enabled). The panic originates from
std.unicode.utf8Decodein the standard library, triggered byevent/input.zigpassing a 32-byte slice where only a 1–4 byte slice is valid.Zig Version: 0.15.2
OS: linux
Reproduce: Run any TUI app, move the mouse in the terminal > process aborts.
Cause: In
src/event/input.zig,parseUtf8Char()receives the full stdin read buffer (e.g. 32 bytes). It callsstd.unicode.utf8Decode(bytes), but Zig’sutf8Decodeonly accepts a slice of length 1–4 (one codepoint).For any other length it hits
else => unreachableand aborts.Fix: Decode only the first codepoint: use
utf8ByteSequenceLength(bytes[0])to getseq_len, then callutf8Decode(bytes[0..seq_len]). On error or truncated input, return an unknown key event.