From 197fe7396e7f63e9471bb317f1341228a0690ce6 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 19:52:50 -0300 Subject: A search pattern with a short \x escape is refused, where mvzr panicked on it Co-Authored-By: Claude Opus 5.5 --- src/regexp.zig | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/regexp.zig b/src/regexp.zig index fe68585d..f6d540c4 100644 --- a/src/regexp.zig +++ b/src/regexp.zig @@ -62,6 +62,10 @@ pub const Regex = struct { i += 1; piece = pat[i - 1 .. i + 1]; if (pat[i] == 'n') spans = true; + // mvzr slices two hex digits after `\x` without looking, + // so a short one panics it: refuse it here. + if (pat[i] == 'x' and (i + 2 >= pat.len or + !std.ascii.isHex(pat[i + 1]) or !std.ascii.isHex(pat[i + 2]))) return error.Bad; } else if (in_class) { in_class = c != ']'; } else if (c == '[') { @@ -185,3 +189,10 @@ test "the match is the leftmost, however long the line" { try std.testing.expectEqual(@as(usize, 2), f.start); try std.testing.expectEqual(@as(usize, 7), f.end); } + +test "a \\x without two hex digits is refused, not handed to mvzr to panic on" { + for ([_][]const u8{ "\\x", "a\\x1", "\\x1b[\\x", "[\\x]", "\\xg1" }) |pat| + try std.testing.expectError(error.Bad, Regex.compile(pat)); + var rx = try Regex.compile("\\x41"); + try std.testing.expectEqual(@as(usize, 1), (try rx.find("xA", 0, 1, 2)).?.start); +} -- cgit v1.3