]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: never call reflect.Zero(nil)
authorDaniel Martí <mvdan@mvdan.cc>
Sun, 17 Dec 2017 22:32:15 +0000 (22:32 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Tue, 13 Feb 2018 22:18:21 +0000 (22:18 +0000)
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: Rob Pike <r@golang.org>
src/text/template/exec.go
src/text/template/exec_test.go

index 83c38cdf13ce7c39d7b14f789e9c401341a50771..2ed52723498fd50dfb8b14053f321b45cd4b6b4c 100644 (file)
@@ -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)
index d0cda6bd625da787d8dd41fb204ff79ae392fbce..e33e0794dd1fbfd5d6ab4e867825f41530139639 100644 (file)
@@ -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 <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.
        {".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
        {".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},