diff options
| author | Russ Cox <rsc@golang.org> | 2014-10-03 12:22:19 -0400 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2014-10-03 12:22:19 -0400 |
| commit | 904ec0098137f742e0dd96da3bc033d6a0b615d1 (patch) | |
| tree | 6a05a91443927524fcb78ac82df0142d8e6ae71f /src/regexp/syntax/parse.go | |
| parent | d42328c9f749140adf947833e0381fc639c32737 (diff) | |
| parent | c65a47f890e33eeed6ee9d8b6d965a5534fb6e0e (diff) | |
| download | go-904ec0098137f742e0dd96da3bc033d6a0b615d1.tar.xz | |
[dev.garbage] merge default into dev.garbage
Diffstat (limited to 'src/regexp/syntax/parse.go')
| -rw-r--r-- | src/regexp/syntax/parse.go | 34 |
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) |
