Commit 9c6265d3 authored by Russ Cox's avatar Russ Cox

exp/regexp/syntax: fix invalid input parser crash

Reported by Kyle Lemons.

R=r
CC=golang-dev
https://golang.org/cl/4992045
parent 73fd9e7d
...@@ -218,30 +218,31 @@ func (p *parser) op(op Op) *Regexp { ...@@ -218,30 +218,31 @@ func (p *parser) op(op Op) *Regexp {
return p.push(re) return p.push(re)
} }
// repeat replaces the top stack element with itself repeated // repeat replaces the top stack element with itself repeated according to op, min, max.
// according to op. // before is the regexp suffix starting at the repetition operator.
func (p *parser) repeat(op Op, min, max int, whole, opstr, t, lastRepeat string) (string, string, os.Error) { // after is the regexp suffix following after the repetition operator.
// repeat returns an updated 'after' and an error, if any.
func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (string, os.Error) {
flags := p.flags flags := p.flags
if p.flags&PerlX != 0 { if p.flags&PerlX != 0 {
if len(t) > 0 && t[0] == '?' { if len(after) > 0 && after[0] == '?' {
t = t[1:] after = after[1:]
opstr = whole[:len(opstr)+1]
flags ^= NonGreedy flags ^= NonGreedy
} }
if lastRepeat != "" { if lastRepeat != "" {
// In Perl it is not allowed to stack repetition operators: // In Perl it is not allowed to stack repetition operators:
// a** is a syntax error, not a doubled star, and a++ means // a** is a syntax error, not a doubled star, and a++ means
// something else entirely, which we don't support! // something else entirely, which we don't support!
return "", "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]} return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(after)]}
} }
} }
n := len(p.stack) n := len(p.stack)
if n == 0 { if n == 0 {
return "", "", &Error{ErrMissingRepeatArgument, opstr} return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
} }
sub := p.stack[n-1] sub := p.stack[n-1]
if sub.Op >= opPseudo { if sub.Op >= opPseudo {
return "", "", &Error{ErrMissingRepeatArgument, opstr} return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
} }
re := p.newRegexp(op) re := p.newRegexp(op)
re.Min = min re.Min = min
...@@ -250,7 +251,7 @@ func (p *parser) repeat(op Op, min, max int, whole, opstr, t, lastRepeat string) ...@@ -250,7 +251,7 @@ func (p *parser) repeat(op Op, min, max int, whole, opstr, t, lastRepeat string)
re.Sub = re.Sub0[:1] re.Sub = re.Sub0[:1]
re.Sub[0] = sub re.Sub[0] = sub
p.stack[n-1] = re p.stack[n-1] = re
return t, opstr, nil return after, nil
} }
// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation. // concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
...@@ -726,6 +727,7 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) { ...@@ -726,6 +727,7 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
return nil, err return nil, err
} }
case '*', '+', '?': case '*', '+', '?':
before := t
switch t[0] { switch t[0] {
case '*': case '*':
op = OpStar op = OpStar
...@@ -734,26 +736,31 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) { ...@@ -734,26 +736,31 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
case '?': case '?':
op = OpQuest op = OpQuest
} }
if t, repeat, err = p.repeat(op, min, max, t, t[:1], t[1:], lastRepeat); err != nil { after := t[1:]
if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
return nil, err return nil, err
} }
repeat = before
t = after
case '{': case '{':
op = OpRepeat op = OpRepeat
min, max, tt, ok := p.parseRepeat(t) before := t
min, max, after, ok := p.parseRepeat(t)
if !ok { if !ok {
// If the repeat cannot be parsed, { is a literal. // If the repeat cannot be parsed, { is a literal.
p.literal('{') p.literal('{')
t = t[1:] t = t[1:]
break break
} }
opstr := t[:len(t)-len(tt)]
if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max { if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max {
// Numbers were too big, or max is present and min > max. // Numbers were too big, or max is present and min > max.
return nil, &Error{ErrInvalidRepeatSize, opstr} return nil, &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
} }
if t, repeat, err = p.repeat(op, min, max, t, opstr, tt, lastRepeat); err != nil { if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
return nil, err return nil, err
} }
repeat = before
t = after
case '\\': case '\\':
if p.flags&PerlX != 0 && len(t) >= 2 { if p.flags&PerlX != 0 && len(t) >= 2 {
switch t[1] { switch t[1] {
......
...@@ -482,6 +482,7 @@ var onlyPOSIX = []string{ ...@@ -482,6 +482,7 @@ var onlyPOSIX = []string{
"a?*", "a?*",
"a+*", "a+*",
"a{1}*", "a{1}*",
".{1}{2}.{3}",
} }
func TestParseInvalidRegexps(t *testing.T) { func TestParseInvalidRegexps(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment