aboutsummaryrefslogtreecommitdiff
path: root/src/regexp/syntax/parse.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-30 12:08:09 -0400
committerRuss Cox <rsc@golang.org>2014-09-30 12:08:09 -0400
commit9b2b0c8c1663330c64c6cec8feb413f4cf464348 (patch)
treea8cb26cdfe4eb41492e0dbbd8316ffc87d2c58e1 /src/regexp/syntax/parse.go
parentac9218f5f06dabec3ef7682619dd98fe587d6c08 (diff)
downloadgo-9b2b0c8c1663330c64c6cec8feb413f4cf464348.tar.gz
go-9b2b0c8c1663330c64c6cec8feb413f4cf464348.zip
regexp/syntax: reject large repetitions created by nesting small ones
Fixes #7609. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/150270043
Diffstat (limited to 'src/regexp/syntax/parse.go')
-rw-r--r--src/regexp/syntax/parse.go34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
index 08f8d307ae..3dc8ccf503 100644
--- a/src/regexp/syntax/parse.go
+++ b/src/regexp/syntax/parse.go
@@ -244,6 +244,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
if sub.Op >= opPseudo {
return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
}
+
re := p.newRegexp(op)
re.Min = min
re.Max = max
@@ -251,9 +252,42 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
re.Sub = re.Sub0[:1]
re.Sub[0] = sub
p.stack[n-1] = re
+
+ if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) {
+ return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
+ }
+
return after, nil
}
+// repeatIsValid reports whether the repetition re is valid.
+// Valid means that the combination of the top-level repetition
+// and any inner repetitions does not exceed n copies of the
+// innermost thing.
+// This function rewalks the regexp tree and is called for every repetition,
+// so we have to worry about inducing quadratic behavior in the parser.
+// We avoid this by only calling repeatIsValid when min or max >= 2.
+// In that case the depth of any >= 2 nesting can only get to 9 without
+// triggering a parse error, so each subtree can only be rewalked 9 times.
+func repeatIsValid(re *Regexp, n int) bool {
+ if re.Op == OpRepeat {
+ m := re.Max
+ if m < 0 {
+ m = re.Min
+ }
+ if m > n {
+ return false
+ }
+ n /= m
+ }
+ for _, sub := range re.Sub {
+ if !repeatIsValid(sub, n) {
+ return false
+ }
+ }
+ return true
+}
+
// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
func (p *parser) concat() *Regexp {
p.maybeConcat(-1, 0)