Commit 618f88d8 authored by Daniel Martí's avatar Daniel Martí

text/template: never call reflect.Zero(nil)

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í <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent 0ed5bec9
...@@ -691,8 +691,12 @@ func canBeNil(typ reflect.Type) bool { ...@@ -691,8 +691,12 @@ func canBeNil(typ reflect.Type) bool {
// validateType guarantees that the value is valid and assignable to the type. // validateType guarantees that the value is valid and assignable to the type.
func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value { func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
if !value.IsValid() { if !value.IsValid() {
if typ == nil || canBeNil(typ) { if typ == nil {
// An untyped nil interface{}. Accept as a proper nil value. // 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) return reflect.Zero(typ)
} }
s.errorf("invalid value; expected %s", typ) s.errorf("invalid value; expected %s", typ)
......
...@@ -330,6 +330,10 @@ var execTests = []execTest{ ...@@ -330,6 +330,10 @@ var execTests = []execTest{
{"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true}, {"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
{"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true}, {"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
// Edge cases with <no value> with an interface value
{"field on interface", "{{.foo}}", "<no value>", nil, true},
{"field on parenthesized interface", "{{(.).foo}}", "<no value>", nil, true},
// Method calls. // Method calls.
{".Method0", "-{{.Method0}}-", "-M0-", tVal, true}, {".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
{".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true}, {".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment