Bläddra i källkod

Treat invalid groups starting with "(?" as errors (Go regexp is too lenient in this case). Do not pass to regexp2 if TransformRegExp() returns a 'fatal' error. Fixes #216.

Dmitry Panov 5 år sedan
förälder
incheckning
d44c223500
4 ändrade filer med 27 tillägg och 5 borttagningar
  1. 6 1
      builtin_regexp.go
  2. 7 4
      parser/regexp.go
  3. 5 0
      parser/regexp_test.go
  4. 9 0
      regexp_test.go

+ 6 - 1
builtin_regexp.go

@@ -252,9 +252,14 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) {
 		}
 		}
 		wrapper = (*regexpWrapper)(pattern)
 		wrapper = (*regexpWrapper)(pattern)
 	} else {
 	} else {
+		if re2Str == "" {
+			err = err1
+			return
+		}
 		wrapper2, err = compileRegexp2(patternStr, multiline, ignoreCase)
 		wrapper2, err = compileRegexp2(patternStr, multiline, ignoreCase)
 		if err != nil {
 		if err != nil {
-			err = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", patternStr, err1)
+			err = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", patternStr, err)
+			return
 		}
 		}
 	}
 	}
 
 

+ 7 - 4
parser/regexp.go

@@ -95,8 +95,13 @@ func (self *_RegExp_parser) scanGroup() {
 	str := self.str[self.chrOffset:]
 	str := self.str[self.chrOffset:]
 	if len(str) > 1 { // A possibility of (?= or (?!
 	if len(str) > 1 { // A possibility of (?= or (?!
 		if str[0] == '?' {
 		if str[0] == '?' {
-			if str[1] == '=' || str[1] == '!' {
+			ch := str[1]
+			switch {
+			case ch == '=' || ch == '!':
 				self.error(-1, "re2: Invalid (%s) <lookahead>", self.str[self.chrOffset:self.chrOffset+2])
 				self.error(-1, "re2: Invalid (%s) <lookahead>", self.str[self.chrOffset:self.chrOffset+2])
+			case ch != ':' && ch != '<':
+				self.error(-1, "Invalid group")
+				self.invalid = true
 			}
 			}
 		}
 		}
 	}
 	}
@@ -305,7 +310,6 @@ func (self *_RegExp_parser) scanEscape(inClass bool) {
 	case 'S':
 	case 'S':
 		if inClass {
 		if inClass {
 			self.error(self.chrOffset, "S in class")
 			self.error(self.chrOffset, "S in class")
-			self.invalid = true
 			return
 			return
 		} else {
 		} else {
 			self.goRegexp.WriteString("[^" + WhitespaceChars + "]")
 			self.goRegexp.WriteString("[^" + WhitespaceChars + "]")
@@ -321,9 +325,8 @@ func (self *_RegExp_parser) scanEscape(inClass bool) {
 			if err != nil {
 			if err != nil {
 				self.errors = append(self.errors, err)
 				self.errors = append(self.errors, err)
 			}
 			}
-		} else {
-			// Unescape the character for re2
 		}
 		}
+		// Unescape the character for re2
 		self.pass()
 		self.pass()
 		return
 		return
 	}
 	}

+ 5 - 0
parser/regexp_test.go

@@ -35,6 +35,11 @@ func TestRegExp(t *testing.T) {
 
 
 			test("\\0", "\\0", nil)
 			test("\\0", "\\0", nil)
 
 
+			test("0:(?)", "", "Invalid group")
+			test("(?)", "", "Invalid group")
+			test("(?U)", "", "Invalid group")
+			test("(?)|(?i)", "", "Invalid group")
+			test("(?P<w>)(?P<w>)(?P<D>)", "", "Invalid group")
 		}
 		}
 
 
 		{
 		{

+ 9 - 0
regexp_test.go

@@ -489,6 +489,15 @@ func TestRegexpUnicodeEmptyMatch(t *testing.T) {
 	testScript1(`/(0)0|/gu.exec("0\xef").length === 2`, valueTrue, t)
 	testScript1(`/(0)0|/gu.exec("0\xef").length === 2`, valueTrue, t)
 }
 }
 
 
+func TestRegexpInvalidGroup(t *testing.T) {
+	const SCRIPT = `
+	["?", "(?)"].forEach(function(s) {
+		assert.throws(SyntaxError, function() {new RegExp(s)}, s);
+	});
+	`
+	testScript1(TESTLIB+SCRIPT, _undefined, t)
+}
+
 func BenchmarkRegexpSplitWithBackRef(b *testing.B) {
 func BenchmarkRegexpSplitWithBackRef(b *testing.B) {
 	const SCRIPT = `
 	const SCRIPT = `
 	"aaaaaaaaaaaaaaaaaaaaaaaaa++bbbbbbbbbbbbbbbbbbbbbb+-ccccccccccccccccccccccc".split(/([+-])\1/)
 	"aaaaaaaaaaaaaaaaaaaaaaaaa++bbbbbbbbbbbbbbbbbbbbbb+-ccccccccccccccccccccccc".split(/([+-])\1/)