Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text/template: panic when referencing field of parenthesized argument #21171

Closed
mynameiswhm opened this issue Jul 25, 2017 · 4 comments
Closed
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@mynameiswhm
Copy link

Our team encountered this problem in the wild with Helm template like this one:

{{ (index .Values "non-existent-key").config.host }}

We've fixed it with multiple arguments call to index:

{{ index .Values "non-existent-key" "config" "host" }}

But after some investigation we've narrowed it down to simple case with parentheses and empty interface{} value:

var v interface{}
t.Execute(os.Stdout, v)
...
{{ .foo }} // works fine producing "<no value>"
{{ (.).foo }} // panics

What version of Go are you using (go version)?

go version go1.8.3 darwin/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN="/Users/iesaulenko/gocode/bin"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/iesaulenko/gocode"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.8.3/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.8.3/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/lq/qclr1nvn4tzf_fcnl4xq5t_0fyxkg0/T/go-build885238657=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

package main

import (
	"log"
	"os"
	"text/template"
)

func main() {
	t, _ := template.New("test").Parse(`{{ (.).foo }}`)
	
	var v interface{}
	err := t.Execute(os.Stdout, v)
	if err != nil {
		log.Fatalf("execution failed: %s", err)
	}
}

https://play.golang.org/p/H2lI-3Taxq

What did you expect to see?

<no value>

(which is returned if you change template to {{ .foo }})

What did you see instead?

panic: reflect: Zero(nil) [recovered]
	panic: reflect: Zero(nil)

goroutine 1 [running]:
text/template.errRecover(0xc420099f00)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:146 +0x62
panic(0x10f8c60, 0xc42009c040)
	/usr/local/Cellar/go/1.8.3/libexec/src/runtime/panic.go:489 +0x2cf
reflect.Zero(0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.3/libexec/src/reflect/value.go:2122 +0x134
text/template.(*state).validateType(0xc420099e80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:697 +0x700
text/template.(*state).evalArg(0xc420099e80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11a64e0, 0xc42008e050, 0x100dc56, 0x1205858, ...)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:746 +0x870
text/template.(*state).evalChainNode(0xc420099e80, 0x0, 0x0, 0x0, 0xc4200a0000, 0xc42009c020, 0x1, 0x1, 0x0, 0x0, ...)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:502 +0xf2
text/template.(*state).evalCommand(0xc420099e80, 0x0, 0x0, 0x0, 0xc420090000, 0x0, 0x0, 0x0, 0xc42001d300, 0x1122b3c, ...)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:430 +0x5f3
text/template.(*state).evalPipeline(0xc420099e80, 0x0, 0x0, 0x0, 0xc42008e000, 0x100e162, 0xc420090090, 0x30)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:406 +0xf2
text/template.(*state).walk(0xc420099e80, 0x0, 0x0, 0x0, 0x11a60c0, 0xc420090060)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:232 +0x55a
text/template.(*state).walk(0xc420099e80, 0x0, 0x0, 0x0, 0x11a63c0, 0xc420018360)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:240 +0x139
text/template.(*Template).execute(0xc420012300, 0x11a5280, 0xc42000c018, 0x0, 0x0, 0x0, 0x0)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:195 +0x20a
text/template.(*Template).Execute(0xc420012300, 0x11a5280, 0xc42000c018, 0x0, 0x0, 0x0, 0xc420018240)
	/usr/local/Cellar/go/1.8.3/libexec/src/text/template/exec.go:178 +0x53
main.main()
	/Users/iesaulenko/_go_tmp/src/go.avito.ru/do/foo/main.go:13 +0xbe
exit status 2
@odeke-em
Copy link
Member

I can also reproduce this on go tip 3d9475c, not a regression so marking this for Go1.10.

@odeke-em odeke-em added this to the Go1.10 milestone Jul 26, 2017
@ALTree ALTree added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jul 26, 2017
@odeke-em
Copy link
Member

Sorry @mynameiswhm that we didn't look at this issue during Go1.10. I'll move this to the Go1.11 milestone instead.

@odeke-em odeke-em modified the milestones: Go1.10, Go1.11 Dec 11, 2017
@mvdan mvdan self-assigned this Dec 17, 2017
@mvdan mvdan added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Dec 17, 2017
@mvdan
Copy link
Member

mvdan commented Dec 17, 2017

I believe I have found the fix for this - sending a CL now.

@gopherbot
Copy link

Change https://golang.org/cl/84482 mentions this issue: text/template: never call reflect.Zero(nil)

@golang golang locked and limited conversation to collaborators Feb 13, 2019
@rsc rsc unassigned mvdan Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants