From 9ce28b518d9a792d2e3e741bcb38fa046891906e Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Sat, 4 Jun 2022 09:43:40 -0700 Subject: [PATCH] text/template/parse: fix data race on lexer initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, `startParse` would write `lex.breakOK` and `lex.continueOK` when the lexer goroutine is already running, which is a potential race condition. Makes `breakOK` and `continueOK` configuration flags passed when `lexer` is created, similarly to how `emitComment` works. Fixes #53234 Change-Id: Ia65f6135509a758cd4c5a453b249a174f4fb3e21 Reviewed-on: https://go-review.googlesource.com/c/go/+/410414 Reviewed-by: Eli Bendersky Reviewed-by: Daniel Martí TryBot-Result: Gopher Robot Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/text/template/parse/lex.go | 4 +++- src/text/template/parse/lex_test.go | 4 ++-- src/text/template/parse/parse.go | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index 4c32d261f25b5..29403dd947c93 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -211,7 +211,7 @@ func (l *lexer) drain() { } // lex creates a new scanner for the input string. -func lex(name, input, left, right string, emitComment bool) *lexer { +func lex(name, input, left, right string, emitComment, breakOK, continueOK bool) *lexer { if left == "" { left = leftDelim } @@ -224,6 +224,8 @@ func lex(name, input, left, right string, emitComment bool) *lexer { leftDelim: left, rightDelim: right, emitComment: emitComment, + breakOK: breakOK, + continueOK: continueOK, items: make(chan item), line: 1, startLine: 1, diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go index fcb7e8eacddeb..c5f429667c08c 100644 --- a/src/text/template/parse/lex_test.go +++ b/src/text/template/parse/lex_test.go @@ -394,7 +394,7 @@ var lexTests = []lexTest{ // collect gathers the emitted items into a slice. func collect(t *lexTest, left, right string) (items []item) { - l := lex(t.name, t.input, left, right, true) + l := lex(t.name, t.input, left, right, true, true, true) for { item := l.nextItem() items = append(items, item) @@ -550,7 +550,7 @@ func TestPos(t *testing.T) { func TestShutdown(t *testing.T) { // We need to duplicate template.Parse here to hold on to the lexer. const text = "erroneous{{define}}{{else}}1234" - lexer := lex("foo", text, "{{", "}}", false) + lexer := lex("foo", text, "{{", "}}", false, true, true) _, err := New("root").parseLexer(lexer) if err == nil { t.Fatalf("expected error") diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index 67e2f5b2f4ab1..00c258ad5deab 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -224,8 +224,6 @@ func (t *Tree) startParse(funcs []map[string]any, lex *lexer, treeSet map[string t.vars = []string{"$"} t.funcs = funcs t.treeSet = treeSet - lex.breakOK = !t.hasFunction("break") - lex.continueOK = !t.hasFunction("continue") } // stopParse terminates parsing. @@ -244,7 +242,10 @@ func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tre defer t.recover(&err) t.ParseName = t.Name emitComment := t.Mode&ParseComments != 0 - t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet) + breakOK := !t.hasFunction("break") + continueOK := !t.hasFunction("continue") + lexer := lex(t.Name, text, leftDelim, rightDelim, emitComment, breakOK, continueOK) + t.startParse(funcs, lexer, treeSet) t.text = text t.parse() t.add()