diff --git a/src/regexp/syntax/doc.go b/src/regexp/syntax/doc.go index 8a7d9992a2cfb8..cd94fd8c0813a6 100644 --- a/src/regexp/syntax/doc.go +++ b/src/regexp/syntax/doc.go @@ -51,6 +51,9 @@ Repetitions: Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} reject forms that create a minimum or maximum repetition count above 1000. Unlimited repetitions are not subject to this restriction. +For nested repetitions, the product of the repetition counts must not +exceed 1000. For example, x{10}{10} (product 100) is valid, +but x{10}{101} (product 1010) is not. Grouping: diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go index b77a7dab8e2e60..c5ee93ff23796f 100644 --- a/src/regexp/syntax/parse.go +++ b/src/regexp/syntax/parse.go @@ -433,13 +433,17 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( p.stack[n-1] = re p.checkLimits(re) - if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { + if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, maxRepeat) { return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} } return after, nil } +// maxRepeat is the maximum count allowed in any single repetition x{n,m}. +// The product of all nested repetition counts must also not exceed this limit. +const maxRepeat = 1000 + // 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 @@ -1000,7 +1004,7 @@ func parse(s string, flags Flags) (_ *Regexp, err error) { t = t[1:] break } - if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max { + if min < 0 || min > maxRepeat || max > maxRepeat || max >= 0 && min > max { // Numbers were too big, or max is present and min > max. return nil, &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} } diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go index 9d2f698e258d19..eb58e389224a9d 100644 --- a/src/regexp/syntax/parse_test.go +++ b/src/regexp/syntax/parse_test.go @@ -214,6 +214,7 @@ var parseTests = []parseTest{ // Valid repetitions. {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``}, {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``}, + {`(?:[a-z]{4}){0,250}`, ``}, // nested repeat product 4*250 = 1000, at the limit // Valid nesting. {strings.Repeat("(", 999) + strings.Repeat(")", 999), ``}, @@ -500,6 +501,7 @@ var invalidRegexps = []string{ `a{100000}`, // too much repetition `a{100000,}`, // too much repetition "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", // too much repetition + `(?:[a-z]{4}){0,251}`, // nested repeat product 4*251 > 1000 strings.Repeat("(", 1000) + strings.Repeat(")", 1000), // too deep strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), // too deep "(" + strings.Repeat("(xx?)", 1000) + "){1000}", // too long