From b82d9accd62591c9a9a3fae36a24dd969e2d1c3b Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 22 May 2026 17:42:19 +0200 Subject: [PATCH] Reset Matcher state on match failure Ensure that when a match operation (`find`, `matches`, `lookingAt`) fails, the matcher's hasMatch state is reset to false. This prevents subsequent calls to `group()`, `start()`, `end()` from returning stale match data from previous successful matches, and instead correctly throws `IllegalStateException`. * Closes https://github.com/google/re2j/issues/200 * Closes https://github.com/google/re2j/issues/201 --- java/com/google/re2j/Matcher.java | 1 + javatests/com/google/re2j/MatcherTest.java | 44 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/java/com/google/re2j/Matcher.java b/java/com/google/re2j/Matcher.java index 678186d0..d4abd1a9 100644 --- a/java/com/google/re2j/Matcher.java +++ b/java/com/google/re2j/Matcher.java @@ -369,6 +369,7 @@ private boolean genMatch(int startByte, int anchor) { // From the JDK docs, looks like no. boolean ok = pattern.re2().match(matcherInput, startByte, inputLength, anchor, groups, 1); if (!ok) { + hasMatch = false; return false; } hasMatch = true; diff --git a/javatests/com/google/re2j/MatcherTest.java b/javatests/com/google/re2j/MatcherTest.java index 4f24ae2e..67fcb065 100644 --- a/javatests/com/google/re2j/MatcherTest.java +++ b/javatests/com/google/re2j/MatcherTest.java @@ -524,4 +524,48 @@ public void testPatternLongestMatch() { assertEquals("aaa bbb", text.substring(matcher.start(), matcher.end())); } } + + @Test + public void testStateResetOnFailure() { + { + Matcher m = Pattern.compile("abc").matcher("abc"); + assertTrue(m.find()); + assertEquals("abc", m.group()); + + // Subsequent find() fails + assertFalse(m.find()); + try { + m.group(); + fail("Should have thrown IllegalStateException"); + } catch (IllegalStateException expected) { + // Expected + } + try { + m.start(); + fail("Should have thrown IllegalStateException"); + } catch (IllegalStateException expected) { + // Expected + } + try { + m.end(); + fail("Should have thrown IllegalStateException"); + } catch (IllegalStateException expected) { + // Expected + } + } + + { + // Test matches() then find() + Matcher m = Pattern.compile("([1-5][0-9]{2})-([1-5][0-9]{2})").matcher("201-299"); + assertTrue(m.matches()); + assertEquals("201-299", m.group()); + assertFalse(m.find()); // should fail + try { + m.group(1); + fail("Should have thrown IllegalStateException"); + } catch (IllegalStateException expected) { + // Expected + } + } + } }