mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-05-17 00:26:36 +03:00
lib/regexutil: prevent panic error parsing regexp: expression nests too deeply
Previously regex simplify function made an attempt to parse string representation of simplified regex. And it could produce runtime panic due to std lib specification: ``` // Simplify returns a regexp equivalent to re but without counted repetitions // and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/. // The resulting regexp will execute correctly but its string representation // will not produce the same parse tree, because capturing parentheses // may have been duplicated or removed. ``` This commit ignores simplified regex parsing error and returns back original regex. It results into possible missing simplification of some niche regex patterns. But it's extremely rare cases rarely seen in production. So the tradeoff is acceptable. Fixes victoriaMetrics/victoriaLogs/issues/1112
This commit is contained in:
@@ -32,6 +32,8 @@ See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-rel
|
||||
* FEATURE: [dashboards/vmauth](https://grafana.com/grafana/dashboards/21394): add `Request body buffering duration` panel to the `Troubleshooting` section. This panel shows the time spent buffering incoming client request bodies, helping identify slow client uploads and potential concurrency issues. The panel is only available when `-requestBufferSize` is non-zero. See [#10309](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10309).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/), [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/), `vminsert` and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): enable [ingestion](https://docs.victoriametrics.com/victoriametrics/vmagent/#metric-metadata) and in-memory [storage](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#metrics-metadata) of metrics metadata by default. Metadata ingestion can be disabled with `-enableMetadata=false`. See [#2974](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2974).
|
||||
|
||||
* BUGFIX: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): prevent panic `error parsing regexp: expression nests too deeply` triggered by large repetition ranges in regex. See [VictoriaLogs#1112](https://github.com/VictoriaMetrics/VictoriaLogs/issues/1112).
|
||||
|
||||
## [v1.136.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.136.0)
|
||||
|
||||
Released at 2026-02-13
|
||||
|
||||
@@ -17,6 +17,8 @@ func TestNewRegexFailure(t *testing.T) {
|
||||
|
||||
f("[foo")
|
||||
f("(foo")
|
||||
// Trigger syntax.ErrInvalidRepeatOp
|
||||
f("a{0,10000}")
|
||||
}
|
||||
|
||||
func TestRegexMatchString(t *testing.T) {
|
||||
@@ -144,6 +146,10 @@ func TestRegexMatchString(t *testing.T) {
|
||||
f("foo(bar|baz)", "a fooxfoobaz a", true)
|
||||
f("foo(bar|baz)", "a fooxfooban a", false)
|
||||
f("foo(bar|baz)", "a fooxfooban foobar a", true)
|
||||
|
||||
// Trigger syntax.ErrNestingDepth
|
||||
// See https://github.com/VictoriaMetrics/VictoriaLogs/issues/1112
|
||||
f("a{0,1000}", "a", true)
|
||||
}
|
||||
|
||||
func TestGetLiterals(t *testing.T) {
|
||||
|
||||
@@ -202,7 +202,11 @@ func simplifyRegex(expr string, keepAnchors bool) (string, string) {
|
||||
// Cannot parse the regexp. Return it all as prefix.
|
||||
return expr, ""
|
||||
}
|
||||
sre = simplifyRegexp(sre, keepAnchors, keepAnchors)
|
||||
sre, ok := simplifyRegexp(sre, keepAnchors, keepAnchors)
|
||||
if !ok {
|
||||
// The regexp is valid but cannot be simplified. Return it all as suffix.
|
||||
return "", expr
|
||||
}
|
||||
if sre == emptyRegexp {
|
||||
return "", ""
|
||||
}
|
||||
@@ -218,7 +222,10 @@ func simplifyRegex(expr string, keepAnchors bool) (string, string) {
|
||||
if len(sre.Sub) == 0 {
|
||||
return prefix, ""
|
||||
}
|
||||
sre = simplifyRegexp(sre, true, keepAnchors)
|
||||
sreNew, ok := simplifyRegexp(sre, true, keepAnchors)
|
||||
if ok {
|
||||
sre = sreNew
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := syntax.Compile(sre); err != nil {
|
||||
@@ -232,7 +239,7 @@ func simplifyRegex(expr string, keepAnchors bool) (string, string) {
|
||||
return prefix, s
|
||||
}
|
||||
|
||||
func simplifyRegexp(sre *syntax.Regexp, keepBeginOp, keepEndOp bool) *syntax.Regexp {
|
||||
func simplifyRegexp(sre *syntax.Regexp, keepBeginOp, keepEndOp bool) (*syntax.Regexp, bool) {
|
||||
s := sre.String()
|
||||
for {
|
||||
sre = simplifyRegexpExt(sre, keepBeginOp, keepEndOp)
|
||||
@@ -244,10 +251,19 @@ func simplifyRegexp(sre *syntax.Regexp, keepBeginOp, keepEndOp bool) *syntax.Reg
|
||||
}
|
||||
sNew := sre.String()
|
||||
if sNew == s {
|
||||
return sre
|
||||
return sre, true
|
||||
}
|
||||
sre = mustParseRegexp(sNew)
|
||||
s = sNew
|
||||
|
||||
sreNew, err := parseRegexp(sNew)
|
||||
if err != nil {
|
||||
// Parsing errors can occur due to deep nesting limits or other validation parameters.
|
||||
// This usually happens when the Simplify method returns an optimized regex that is technically valid
|
||||
// but exceeds internal complexity thresholds.
|
||||
// See https://github.com/VictoriaMetrics/VictoriaLogs/issues/1112
|
||||
return nil, false
|
||||
}
|
||||
sre = sreNew
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user