From fcaf4250427310c2b0405e00d17e3a1b5b015221 Mon Sep 17 00:00:00 2001 From: Ade Attwood Date: Wed, 29 May 2024 17:22:37 +0100 Subject: [PATCH] fix: infinite loop when using .* patterns Summary: When we are using `.*` patterns, this causes an infinite loop. What happens is we are adding text to the end and then replacing that. Its only when we are matching the end of the output string. We can detect this when the starting point is the same as the end point and the match is "" (an empty string). If we hit this condition we can get out and return the output that has been replaced. Test Plan: Test in CI --- src/lib.rs | 6 ++++++ tests/features/regex.feature | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5ff0528..60862f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,12 @@ pub fn replace(search: &String, replace: String, input: String) -> String { let start = search_match.start(); let end = search_match.end(); + // Prevent an infinite loop. If we hit this condition we will keep adding a new replacement + // to the end. + if start == end { + break; + } + let mut replacement = String::new(); match search_pattern.captures(&output[start..end]) { Some(captures) => { diff --git a/tests/features/regex.feature b/tests/features/regex.feature index 3e3ad5c..0a85b5c 100644 --- a/tests/features/regex.feature +++ b/tests/features/regex.feature @@ -22,4 +22,16 @@ Feature: Regex search and replace Given Search is '(\w+' And Replace is 'new' And Input is 'this is a' - Then Output is 'this is a' + Then Output is 'this is a' + + Scenario: You can replace a pattern with a dot in it like a css class name + Given Search is '.testing' + And Replace is '.another' + And Input is '.testing {' + Then Output is '.another {' + + Scenario: You can replace a pattern that grabs all the text + Given Search is '.*' + And Replace is '.another' + And Input is '.testing {' + Then Output is '.another'