From 2800956682af70ec2fd79960c052b9aaeef2ad52 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 8 Sep 2011 11:12:11 +1000 Subject: [release-branch.r60] template: fix deadlock. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ««« CL 4963054 / c581abafc917 template: fix deadlock. No need for lexInsideAction to loop. Fixes #2217. R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/4963054 »»» R=dsymonds CC=golang-dev https://golang.org/cl/4974068 --- src/pkg/template/parse/lex.go | 84 +++++++++++++++++++------------------- src/pkg/template/parse/lex_test.go | 14 +++++++ 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/pkg/template/parse/lex.go b/src/pkg/template/parse/lex.go index 7ec4e920bd..83ad6c628b 100644 --- a/src/pkg/template/parse/lex.go +++ b/src/pkg/template/parse/lex.go @@ -278,53 +278,51 @@ func lexInsideAction(l *lexer) stateFn { // Either number, quoted string, or identifier. // Spaces separate and are ignored. // Pipe symbols separate and are emitted. - for { - if strings.HasPrefix(l.input[l.pos:], rightDelim) { - return lexRightDelim + if strings.HasPrefix(l.input[l.pos:], rightDelim) { + return lexRightDelim + } + switch r := l.next(); { + case r == eof || r == '\n': + return l.errorf("unclosed action") + case isSpace(r): + l.ignore() + case r == ':': + if l.next() != '=' { + return l.errorf("expected :=") } - switch r := l.next(); { - case r == eof || r == '\n': - return l.errorf("unclosed action") - case isSpace(r): - l.ignore() - case r == ':': - if l.next() != '=' { - return l.errorf("expected :=") + l.emit(itemColonEquals) + case r == '|': + l.emit(itemPipe) + case r == '"': + return lexQuote + case r == '`': + return lexRawQuote + case r == '$': + return lexIdentifier + case r == '\'': + return lexChar + case r == '.': + // special look-ahead for ".field" so we don't break l.backup(). + if l.pos < len(l.input) { + r := l.input[l.pos] + if r < '0' || '9' < r { + return lexIdentifier // itemDot comes from the keyword table. } - l.emit(itemColonEquals) - case r == '|': - l.emit(itemPipe) - case r == '"': - return lexQuote - case r == '`': - return lexRawQuote - case r == '$': - return lexIdentifier - case r == '\'': - return lexChar - case r == '.': - // special look-ahead for ".field" so we don't break l.backup(). - if l.pos < len(l.input) { - r := l.input[l.pos] - if r < '0' || '9' < r { - return lexIdentifier // itemDot comes from the keyword table. - } - } - fallthrough // '.' can start a number. - case r == '+' || r == '-' || ('0' <= r && r <= '9'): - l.backup() - return lexNumber - case isAlphaNumeric(r): - l.backup() - return lexIdentifier - case r <= unicode.MaxASCII && unicode.IsPrint(r): - l.emit(itemChar) - return lexInsideAction - default: - return l.errorf("unrecognized character in action: %#U", r) } + fallthrough // '.' can start a number. + case r == '+' || r == '-' || ('0' <= r && r <= '9'): + l.backup() + return lexNumber + case isAlphaNumeric(r): + l.backup() + return lexIdentifier + case r <= unicode.MaxASCII && unicode.IsPrint(r): + l.emit(itemChar) + return lexInsideAction + default: + return l.errorf("unrecognized character in action: %#U", r) } - return nil + return lexInsideAction } // lexIdentifier scans an alphanumeric or field. diff --git a/src/pkg/template/parse/lex_test.go b/src/pkg/template/parse/lex_test.go index 2ad91d5fa4..d71c8e66df 100644 --- a/src/pkg/template/parse/lex_test.go +++ b/src/pkg/template/parse/lex_test.go @@ -184,6 +184,20 @@ var lexTests = []lexTest{ tLeft, {itemError, `bad number syntax: "3k"`}, }}, + + // Fixed bugs + // Many elements in an action blew the lookahead until + // we made lexInsideAction not loop. + {"long pipeline deadlock", "{{|||||}}", []item{ + tLeft, + tPipe, + tPipe, + tPipe, + tPipe, + tPipe, + tRight, + tEOF, + }}, } // collect gathers the emitted items into a slice. -- cgit v1.2.3-54-g00ecf