From: Samuel Tan Date: Fri, 17 Nov 2017 23:47:33 +0000 (-0800) Subject: html/template: reset templates orphaned by (*Template).New X-Git-Tag: go1.10beta2~162 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6af8c0d812f7bd20d81df986c3ed425f3251e8dc;p=gostls13.git html/template: reset templates orphaned by (*Template).New If (*Template).New replaces an existing template, reset the existing template that is going to be replaced so that any later attempt to execute this orphaned template will fail. Fixes #22780 Change-Id: I0e058f42c1542c86d19dc5f6c4e1e859e670a4a2 Reviewed-on: https://go-review.googlesource.com/78542 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor --- diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go index 92f12ca0e0..2312c9c1c3 100644 --- a/src/html/template/escape_test.go +++ b/src/html/template/escape_test.go @@ -1903,3 +1903,25 @@ func BenchmarkEscapedExecute(b *testing.B) { buf.Reset() } } + +// Covers issue 22780. +func TestOrphanedTemplate(t *testing.T) { + t1 := Must(New("foo").Parse(`link1`)) + t2 := Must(t1.New("foo").Parse(`bar`)) + + var b bytes.Buffer + const wantError = `template: "foo" is an incomplete or empty template` + if err := t1.Execute(&b, "javascript:alert(1)"); err == nil { + t.Fatal("expected error executing t1") + } else if gotError := err.Error(); gotError != wantError { + t.Fatalf("got t1 execution error:\n\t%s\nwant:\n\t%s", gotError, wantError) + } + b.Reset() + if err := t2.Execute(&b, nil); err != nil { + t.Fatalf("error executing t1: %s", err) + } + const want = "bar" + if got := b.String(); got != want { + t.Fatalf("t2 rendered %q, want %q", got, want) + } +} diff --git a/src/html/template/template.go b/src/html/template/template.go index d77aa3d7df..9dc066855f 100644 --- a/src/html/template/template.go +++ b/src/html/template/template.go @@ -300,6 +300,10 @@ func New(name string) *Template { // New allocates a new HTML template associated with the given one // and with the same delimiters. The association, which is transitive, // allows one template to invoke another with a {{template}} action. +// +// If a template with the given name already exists, the new HTML template +// will replace it. The existing template will be reset and disassociated with +// t. func (t *Template) New(name string) *Template { t.nameSpace.mu.Lock() defer t.nameSpace.mu.Unlock() @@ -314,6 +318,10 @@ func (t *Template) new(name string) *Template { nil, t.nameSpace, } + if existing, ok := tmpl.set[name]; ok { + emptyTmpl := New(existing.Name()) + *existing = *emptyTmpl + } tmpl.set[name] = tmpl return tmpl }