120 lines
4.0 KiB
Diff
120 lines
4.0 KiB
Diff
From 94fbe72e320175d2655c04bee76974941edb2491 Mon Sep 17 00:00:00 2001
|
|
From: Russ Cox <rsc@golang.org>
|
|
Date: Wed, 2 Feb 2022 16:41:32 -0500
|
|
Subject: [PATCH] regexp/syntax: reject very deeply nested regexps in Parse
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
The regexp code assumes it can recurse over the structure of
|
|
a regexp safely. Go's growable stacks make that reasonable
|
|
for all plausible regexps, but implausible ones can reach the
|
|
“infinite recursion?” stack limit.
|
|
|
|
This CL limits the depth of any parsed regexp to 1000.
|
|
That is, the depth of the parse tree is required to be ≤ 1000.
|
|
Regexps that require deeper parse trees will return ErrInternalError.
|
|
A future CL will change the error to ErrInvalidDepth,
|
|
but using ErrInternalError for now avoids introducing new API
|
|
in point releases when this is backported.
|
|
|
|
Fixes #51112.
|
|
Fixes #51118.
|
|
|
|
Change-Id: I97d2cd82195946eb43a4ea8561f5b95f91fb14c5
|
|
Reviewed-on: https://go-review.googlesource.com/c/go/+/384616
|
|
Trust: Russ Cox <rsc@golang.org>
|
|
Run-TryBot: Russ Cox <rsc@golang.org>
|
|
Reviewed-by: Ian Lance Taylor <iant@golang.org>
|
|
Reviewed-on: https://go-review.googlesource.com/c/go/+/384854
|
|
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
|
|
Conflict: NA
|
|
Reference: https://go-review.googlesource.com/c/go/+/384854/
|
|
---
|
|
src/regexp/syntax/parse.go | 19 ++++++-------------
|
|
src/regexp/syntax/parse_test.go | 5 +++++
|
|
2 files changed, 11 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
|
|
index 67254d6..3792960 100644
|
|
--- a/src/regexp/syntax/parse.go
|
|
+++ b/src/regexp/syntax/parse.go
|
|
@@ -43,7 +43,6 @@ const (
|
|
ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator"
|
|
ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression"
|
|
ErrUnexpectedParen ErrorCode = "unexpected )"
|
|
- ErrNestingDepth ErrorCode = "expression nests too deeply"
|
|
)
|
|
|
|
func (e ErrorCode) String() string {
|
|
@@ -266,7 +265,7 @@ func (p *parser) checkHeight(re *Regexp) {
|
|
}
|
|
}
|
|
if p.calcHeight(re, true) > maxHeight {
|
|
- panic(ErrNestingDepth)
|
|
+ panic(ErrInternalError)
|
|
}
|
|
}
|
|
|
|
@@ -578,16 +577,12 @@ func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
|
|
// frees (passes to p.reuse) any removed *Regexps.
|
|
//
|
|
// For example,
|
|
-//
|
|
-// ABC|ABD|AEF|BCX|BCY
|
|
-//
|
|
+// ABC|ABD|AEF|BCX|BCY
|
|
// simplifies by literal prefix extraction to
|
|
-//
|
|
-// A(B(C|D)|EF)|BC(X|Y)
|
|
-//
|
|
+// A(B(C|D)|EF)|BC(X|Y)
|
|
// which simplifies by character class introduction to
|
|
+// A(B[CD]|EF)|BC[XY]
|
|
//
|
|
-// A(B[CD]|EF)|BC[XY]
|
|
func (p *parser) factor(sub []*Regexp) []*Regexp {
|
|
if len(sub) < 2 {
|
|
return sub
|
|
@@ -897,10 +892,8 @@ func parse(s string, flags Flags) (_ *Regexp, err error) {
|
|
panic(r)
|
|
case nil:
|
|
// ok
|
|
- case ErrInternalError: // too big
|
|
+ case ErrInternalError:
|
|
err = &Error{Code: ErrInternalError, Expr: s}
|
|
- case ErrNestingDepth:
|
|
- err = &Error{Code: ErrNestingDepth, Expr: s}
|
|
}
|
|
}()
|
|
|
|
@@ -1943,7 +1936,7 @@ func appendClass(r []rune, x []rune) []rune {
|
|
return r
|
|
}
|
|
|
|
-// appendFoldedClass returns the result of appending the case folding of the class x to the class r.
|
|
+// appendFolded returns the result of appending the case folding of the class x to the class r.
|
|
func appendFoldedClass(r []rune, x []rune) []rune {
|
|
for i := 0; i < len(x); i += 2 {
|
|
r = appendFoldedRange(r, x[i], x[i+1])
|
|
diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go
|
|
index 6044da6..67e3c56 100644
|
|
--- a/src/regexp/syntax/parse_test.go
|
|
+++ b/src/regexp/syntax/parse_test.go
|
|
@@ -207,6 +207,11 @@ 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})`, ``},
|
|
+
|
|
+ // Valid nesting.
|
|
+ {strings.Repeat("(", 999) + strings.Repeat(")", 999), ``},
|
|
+ {strings.Repeat("(?:", 999) + strings.Repeat(")*", 999), ``},
|
|
+ {"(" + strings.Repeat("|", 12345) + ")", ``}, // not nested at all
|
|
}
|
|
|
|
const testFlags = MatchNL | PerlX | UnicodeGroups
|
|
--
|
|
2.33.0
|
|
|