Skip to content

html/template: data race in Execute #39807

Closed
@bep

Description

@bep
go version go1.14.3 darwin/amd64

Building the below program with go build -race and then running it fails:

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	jsTempl := `
{{- define "jstempl" -}}
var foo = "bar";
{{- end -}}
<script type="application/javascript">
{{ template "jstempl" $ }}
</script>
`

	tpl := template.New("")
	_, err := tpl.New("templ.html").Parse(jsTempl)
	if err != nil {
		log.Fatal(err)
	}

	const numTemplates = 20

	for i := 0; i < numTemplates; i++ {
		_, err = tpl.New(fmt.Sprintf("main%d.html", i)).Parse(`{{ template "templ.html" . }}`)
		if err != nil {
			log.Fatal(err)
		}
	}

	for i := 1; i <= 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < numTemplates; j++ {
				templ := tpl.Lookup(fmt.Sprintf("main%d.html", j))
				if err := templ.Execute(ioutil.Discard, nil); err != nil {
					log.Fatal(err)
				}

			}
		}()
	}

	wg.Wait()
}
WARNING: DATA RACE

WARNING: DATA RACE
Write at 0x00c00011c540 by goroutine 32:
  runtime.mapassign_faststr()
      /Users/bep/dev/go/dump/go/src/runtime/map_faststr.go:202 +0x0
  text/template.(*Template).associate()
      /Users/bep/dev/go/dump/go/src/text/template/template.go:227 +0x1a8
  text/template.(*Template).AddParseTree()
      /Users/bep/dev/go/dump/go/src/text/template/template.go:133 +0x2cc
  html/template.(*escaper).commit()
      /Users/bep/dev/go/dump/go/src/html/template/escape.go:810 +0x2c5
  html/template.escapeTemplate()
      /Users/bep/dev/go/dump/go/src/html/template/escape.go:38 +0x324
  html/template.(*Template).escape()
      /Users/bep/dev/go/dump/go/src/html/template/template.go:102 +0x349
  html/template.(*Template).Execute()
      /Users/bep/dev/go/dump/go/src/html/template/template.go:119 +0x3c
  main.main.func1()
      /Users/bep/dev/go/bep/temp/main.go:46 +0x177

Previous read at 0x00c00011c540 by goroutine 28:
runtime.mapaccess1_faststr()
/Users/bep/dev/go/dump/go/src/runtime/map_faststr.go:12 +0x0
text/template.(*state).walkTemplate()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:399 +0x13b
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:268 +0x2be
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:263 +0x195
text/template.(*Template).execute()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:220 +0x2fb
text/template.(*Template).Execute()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:203 +0xd2
html/template.(*Template).Execute()
/Users/bep/dev/go/dump/go/src/html/template/template.go:122 +0x7f
main.main.func1()
/Users/bep/dev/go/bep/temp/main.go:46 +0x177

Goroutine 32 (running) created at:
main.main()
/Users/bep/dev/go/bep/temp/main.go:42 +0x2de

Goroutine 28 (running) created at:
main.main()
/Users/bep/dev/go/bep/temp/main.go:42 +0x2de

==================
WARNING: DATA RACE
Write at 0x00c0000ac0b0 by goroutine 32:
text/template.(*Template).associate()
/Users/bep/dev/go/dump/go/src/text/template/template.go:227 +0x1bd
text/template.(*Template).AddParseTree()
/Users/bep/dev/go/dump/go/src/text/template/template.go:133 +0x2cc
html/template.(*escaper).commit()
/Users/bep/dev/go/dump/go/src/html/template/escape.go:810 +0x2c5
html/template.escapeTemplate()
/Users/bep/dev/go/dump/go/src/html/template/escape.go:38 +0x324
html/template.(*Template).escape()
/Users/bep/dev/go/dump/go/src/html/template/template.go:102 +0x349
html/template.(*Template).Execute()
/Users/bep/dev/go/dump/go/src/html/template/template.go:119 +0x3c
main.main.func1()
/Users/bep/dev/go/bep/temp/main.go:46 +0x177

Previous read at 0x00c0000ac0b0 by goroutine 28:
text/template.(*state).walkTemplate()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:399 +0x14e
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:268 +0x2be
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:263 +0x195
text/template.(*state).walkTemplate()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:413 +0x3cd
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:268 +0x2be
text/template.(*state).walk()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:263 +0x195
text/template.(*Template).execute()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:220 +0x2fb
text/template.(*Template).Execute()
/Users/bep/dev/go/dump/go/src/text/template/exec.go:203 +0xd2
html/template.(*Template).Execute()
/Users/bep/dev/go/dump/go/src/html/template/template.go:122 +0x7f
main.main.func1()
/Users/bep/dev/go/bep/temp/main.go:46 +0x177

Goroutine 32 (running) created at:
main.main()
/Users/bep/dev/go/bep/temp/main.go:42 +0x2de

Goroutine 28 (running) created at:
main.main()
/Users/bep/dev/go/bep/temp/main.go:42 +0x2de

Found 2 data race(s)


Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions