Fix containsStringMatcher() when the text contains multiple occurrences of a substring (#431)

Signed-off-by: Marco Pracucci <marco@pracucci.com>
This commit is contained in:
Marco Pracucci 2023-03-01 12:18:30 +01:00 committed by GitHub
parent c77900d58e
commit 2e0ecc013f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 18 deletions

View file

@ -397,27 +397,36 @@ type containsStringMatcher struct {
func (m *containsStringMatcher) Matches(s string) bool {
for _, substr := range m.substrings {
if m.right != nil && m.left != nil {
pos := strings.Index(s, substr)
searchStartPos := 0
for {
pos := strings.Index(s[searchStartPos:], substr)
if pos < 0 {
continue
break
}
// Since we started searching from searchStartPos, we have to add that offset
// to get the actual position of the substring inside the text.
pos += searchStartPos
// If both the left and right matchers match, then we can stop searching because
// we've found a match.
if m.left.Matches(s[:pos]) && m.right.Matches(s[pos+len(substr):]) {
return true
}
continue
// Continue searching for another occurrence of the substring inside the text.
searchStartPos = pos + 1
}
} else if m.left != nil {
// If we have to check for characters on the left then we need to match a suffix.
if m.left != nil {
if strings.HasSuffix(s, substr) && m.left.Matches(s[:len(s)-len(substr)]) {
return true
}
continue
}
if m.right != nil {
} else if m.right != nil {
if strings.HasPrefix(s, substr) && m.right.Matches(s[len(substr):]) {
return true
}
continue
}
}
return false

View file

@ -19,7 +19,6 @@ import (
"testing"
"time"
"github.com/grafana/regexp"
"github.com/grafana/regexp/syntax"
"github.com/stretchr/testify/require"
)
@ -60,6 +59,7 @@ var (
"foo", " foo bar", "bar", "buzz\nbar", "bar foo", "bfoo", "\n", "\nfoo", "foo\n", "hello foo world", "hello foo\n world", "",
"FOO", "Foo", "OO", "Oo", "\nfoo\n", strings.Repeat("f", 20), "prometheus", "prometheus_api_v1", "prometheus_api_v1_foo",
"10.0.1.20", "10.0.2.10", "10.0.3.30", "10.0.4.40",
"foofoo0", "foofoo",
}
)
@ -72,9 +72,7 @@ func TestNewFastRegexMatcher(t *testing.T) {
t.Parallel()
m, err := NewFastRegexMatcher(r)
require.NoError(t, err)
re, err := regexp.Compile("^(?:" + r + ")$")
require.NoError(t, err)
require.Equal(t, re.MatchString(v), m.MatchString(v))
require.Equal(t, m.re.MatchString(v), m.MatchString(v))
})
}
@ -329,3 +327,24 @@ func RandStringRunes(n int) string {
}
return string(b)
}
func FuzzFastRegexMatcher_WithStaticallyDefinedRegularExpressions(f *testing.F) {
// Create all matchers.
matchers := make([]*FastRegexMatcher, 0, len(regexes))
for _, re := range regexes {
m, err := NewFastRegexMatcher(re)
require.NoError(f, err)
matchers = append(matchers, m)
}
// Add known values to seed corpus.
for _, v := range values {
f.Add(v)
}
f.Fuzz(func(t *testing.T, text string) {
for _, m := range matchers {
require.Equalf(t, m.re.MatchString(text), m.MatchString(text), "regexp: %s text: %s", m.re.String(), text)
}
})
}