From 6356d1a34f6b6842df3c6fd7dc585eae53fbbd56 Mon Sep 17 00:00:00 2001 From: Adam Crume Date: Mon, 19 Jun 2017 18:36:17 -0700 Subject: [PATCH] Move has_visited check to the top of the loop in backtrack::Bounded::step This prevents us from executing instructions if they have been executed before, rather than returning after the instruction has already been executed. Fixes #375 --- src/backtrack.rs | 6 +++--- tests/crazy.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/backtrack.rs b/src/backtrack.rs index 78bc39e93e..089681c30c 100644 --- a/src/backtrack.rs +++ b/src/backtrack.rs @@ -216,6 +216,9 @@ impl<'a, 'm, 'r, 's, I: Input> Bounded<'a, 'm, 'r, 's, I> { // from the stack. Namely, if we're pushing a job only to run it // next, avoid the push and just mutate `ip` (and possibly `at`) // in place. + if self.has_visited(ip, at) { + return false; + } match self.prog[ip] { Match(slot) => { if slot < self.matches.len() { @@ -275,9 +278,6 @@ impl<'a, 'm, 'r, 's, I: Input> Bounded<'a, 'm, 'r, 's, I> { return false; } } - if self.has_visited(ip, at) { - return false; - } } } diff --git a/tests/crazy.rs b/tests/crazy.rs index ade839ade1..c7c5723084 100644 --- a/tests/crazy.rs +++ b/tests/crazy.rs @@ -47,6 +47,20 @@ mat!(negclass_space_comma, r"[^,\s]", ", a", Some((2, 3))); mat!(negclass_comma_space, r"[^\s,]", " ,a", Some((2, 3))); mat!(negclass_ascii, r"[^[:alpha:]Z]", "A1", Some((1, 2))); +// Test that repeated empty expressions don't loop forever. +mat!(lazy_many_many, r"((?:.*)*?)=", "a=b", Some((0, 2))); +mat!(lazy_many_optional, r"((?:.?)*?)=", "a=b", Some((0, 2))); +mat!(lazy_one_many_many, r"((?:.*)+?)=", "a=b", Some((0, 2))); +mat!(lazy_one_many_optional, r"((?:.?)+?)=", "a=b", Some((0, 2))); +mat!(lazy_range_min_many, r"((?:.*){1,}?)=", "a=b", Some((0, 2))); +mat!(lazy_range_many, r"((?:.*){1,2}?)=", "a=b", Some((0, 2))); +mat!(greedy_many_many, r"((?:.*)*)=", "a=b", Some((0, 2))); +mat!(greedy_many_optional, r"((?:.?)*)=", "a=b", Some((0, 2))); +mat!(greedy_one_many_many, r"((?:.*)+)=", "a=b", Some((0, 2))); +mat!(greedy_one_many_optional, r"((?:.?)+)=", "a=b", Some((0, 2))); +mat!(greedy_range_min_many, r"((?:.*){1,})=", "a=b", Some((0, 2))); +mat!(greedy_range_many, r"((?:.*){1,2})=", "a=b", Some((0, 2))); + // Test that the DFA can handle pathological cases. // (This should result in the DFA's cache being flushed too frequently, which // should cause it to quit and fall back to the NFA algorithm.)