From 618f88d847af9a060a14794859d4f1ea51a08006 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Sun, 17 Dec 2017 22:32:15 +0000 Subject: [PATCH] text/template: never call reflect.Zero(nil) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit It makes no sense to try to get the zero value of a nil type, hence the panic. When we have a nil type, use reflect.ValueOf(nil) instead. This was showing itself if one used a missing field on the data between parentheses, when the data was a nil interface: t := template.Must(template.New("test").Parse(`{{ (.).foo }}`)) var v interface{} t.Execute(os.Stdout, v) Resulting in: panic: reflect: Zero(nil) [recovered] panic: reflect: Zero(nil) Fixes #21171. Change-Id: Ifcc4a0c67e6df425b65bc9f82fde6fcf03828579 Reviewed-on: https://go-review.googlesource.com/84482 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Rob Pike --- src/text/template/exec.go | 6 +++++- src/text/template/exec_test.go | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 83c38cdf13..2ed5272349 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -691,8 +691,12 @@ func canBeNil(typ reflect.Type) bool { // validateType guarantees that the value is valid and assignable to the type. func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { if !value.IsValid() { - if typ == nil || canBeNil(typ) { + if typ == nil { // An untyped nil interface{}. Accept as a proper nil value. + return reflect.ValueOf(nil) + } + if canBeNil(typ) { + // Like above, but use the zero value of the non-nil type. return reflect.Zero(typ) } s.errorf("invalid value; expected %s", typ) diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index d0cda6bd62..e33e0794dd 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -330,6 +330,10 @@ var execTests = []execTest{ {"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true}, {"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true}, + // Edge cases with with an interface value + {"field on interface", "{{.foo}}", "", nil, true}, + {"field on parenthesized interface", "{{(.).foo}}", "", nil, true}, + // Method calls. {".Method0", "-{{.Method0}}-", "-M0-", tVal, true}, {".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true}, -- 2.50.0