From 5a4d657a4e842dff01d7b1f03a269c9daf6c1cd7 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Sun, 17 Nov 2024 16:01:15 +0100 Subject: [PATCH] LibRegex: Avoid generating ForkJumps when jumping to the next alt block Fixes #2398. --- Libraries/LibRegex/RegexOptimizer.cpp | 2 ++ Tests/LibRegex/Regex.cpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Libraries/LibRegex/RegexOptimizer.cpp b/Libraries/LibRegex/RegexOptimizer.cpp index a713867e665..df8b1ac0b2c 100644 --- a/Libraries/LibRegex/RegexOptimizer.cpp +++ b/Libraries/LibRegex/RegexOptimizer.cpp @@ -1197,6 +1197,8 @@ void Optimizer::append_alternation(ByteCode& target, Span alternatives for (auto& patch : patch_locations) { if (!patch.done && node_is(node, patch.source_ip)) { auto value = static_cast(target.size() - patch.target_ip - 1); + if (value == 0) + target[patch.target_ip - 1] = static_cast(OpCodeId::Jump); target[patch.target_ip] = value; patch.done = true; } diff --git a/Tests/LibRegex/Regex.cpp b/Tests/LibRegex/Regex.cpp index 58ed080b274..e975ee96c55 100644 --- a/Tests/LibRegex/Regex.cpp +++ b/Tests/LibRegex/Regex.cpp @@ -1074,7 +1074,7 @@ TEST_CASE(optimizer_char_class_lut) TEST_CASE(optimizer_alternation) { Array tests { - // Pattern, Subject, Expected length + // Pattern, Subject, Expected length [0 == fail] Tuple { "a|"sv, "a"sv, 1u }, Tuple { "a|a|a|a|a|a|a|a|a|b"sv, "a"sv, 1u }, Tuple { "ab|ac|ad|bc"sv, "bc"sv, 2u }, @@ -1084,13 +1084,19 @@ TEST_CASE(optimizer_alternation) Tuple { "^(\\d+|x)"sv, "42"sv, 2u }, // `Repeat' does not add its insn size to the jump target. Tuple { "[0-9]{2}|[0-9]"sv, "92"sv, 2u }, + // Don't ForkJump to the next instruction, rerunning it would produce the same result. see ladybird#2398. + Tuple { "(xxxxxxxxxxxxxxxxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxxx)?b"sv, "xxxxxxxxxxxxxxxxxxxxxxx"sv, 0u }, }; for (auto& test : tests) { Regex re(test.get<0>()); auto result = re.match(test.get<1>()); - EXPECT(result.success); - EXPECT_EQ(result.matches.first().view.length(), test.get<2>()); + if (test.get<2>() != 0) { + EXPECT(result.success); + EXPECT_EQ(result.matches.first().view.length(), test.get<2>()); + } else { + EXPECT(!result.success); + } } }