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

html/template: panic when calling function with untyped nil #24717

Closed
rhysh opened this issue Apr 6, 2018 · 5 comments
Closed

html/template: panic when calling function with untyped nil #24717

rhysh opened this issue Apr 6, 2018 · 5 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@rhysh
Copy link
Contributor

rhysh commented Apr 6, 2018

I get a panic from html/template when I reference an untyped nil within a <script> tag. I bisected, which indicates https://golang.org/cl/95215 / 3cb54c8

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

$ go version
go version devel +542ea5ad91 Wed Apr 4 13:39:34 2018 -0700 darwin/amd64
$ go1.10 version
go version go1.10.1 darwin/amd64

Does this issue reproduce with the latest release?

The issue is present in tip. It is not present in go1.10.1.

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

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/rhys/Library/Caches/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/rhys/go"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/49/zmds5zsn75z1283vtzxyfr5hj7yjq4/T/go-build474956233=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I use the html/template package, and one of my templates involves referencing a data field within a <script> tag. Usually I've set the field's value to some interesting structure I'm trying to pass to a js function. But sometimes it's an untyped nil stored in an interface{} field.

package main

import (
	"html/template"
	"os"
)

func main() {
	data := struct {
		A interface{}
		B interface{}
	}{
		A: (*int)(nil),
		B: nil,
	}

	template.Must(template.New("").Parse("<script>{{.A}}+{{.B}}</script>\n")).Execute(os.Stdout, data)
}

Here's a play link, which runs successfully as expected: https://play.golang.org/p/e54VBAwyVTg

What did you expect to see?

I expected the field's value to be converted to a js-safe JSON representation.

$ go1.10 version
go version go1.10.1 darwin/amd64
$ go1.10 run /tmp/template.go
<script> null +""</script>

(Weird that the untyped nil is written as "" rather than null, but it's been that way since at least Go 1.4.)

What did you see instead?

$ go version
go version devel +542ea5ad91 Wed Apr 4 13:39:34 2018 -0700 darwin/amd64
$ go run /tmp/template.go
<script> null +panic: reflect: call of reflect.Value.Type on zero Value [recovered]
	panic: reflect: call of reflect.Value.Type on zero Value

goroutine 1 [running]:
text/template.errRecover(0xc000055ea8)
	/usr/local/go/src/text/template/exec.go:159 +0x1b9
panic(0x1131860, 0xc000090240)
	/usr/local/go/src/runtime/panic.go:503 +0x1c6
reflect.Value.Type(0x0, 0x0, 0x0, 0x1, 0x1)
	/usr/local/go/src/reflect/value.go:1713 +0x16c
html/template.indirectToJSONMarshaler(0x0, 0x0, 0x203000, 0xc000088d80)
	/usr/local/go/src/html/template/js.go:127 +0xf5
html/template.jsValEscaper(0xc000086430, 0x1, 0x1, 0x0, 0x0)
	/usr/local/go/src/html/template/js.go:138 +0x6bf
reflect.Value.call(0x112cb00, 0x11685f0, 0x13, 0x115ab25, 0x4, 0xc0000901e0, 0x1, 0x1, 0x11596c0, 0x1, ...)
	/usr/local/go/src/reflect/value.go:447 +0x99e
reflect.Value.Call(0x112cb00, 0x11685f0, 0x13, 0xc0000901e0, 0x1, 0x1, 0x1130620, 0xc000086420, 0x94)
	/usr/local/go/src/reflect/value.go:308 +0xa4
text/template.(*state).evalCall(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0x112cb00, 0x11685f0, 0x13, 0x117c580, 0xc000088a80, 0x1163129, ...)
	/usr/local/go/src/text/template/exec.go:688 +0x6ba
text/template.(*state).evalFunction(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0xc000088a50, 0x117c580, 0xc000088a80, 0xc000086320, 0x1, 0x1, ...)
	/usr/local/go/src/text/template/exec.go:556 +0x172
text/template.(*state).evalCommand(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0xc000088a80, 0x0, 0x0, 0x0, 0x1130620, 0xc0000900b0, ...)
	/usr/local/go/src/text/template/exec.go:453 +0x5f4
text/template.(*state).evalPipeline(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0xc0000e40c0, 0x0, 0x0, 0x98)
	/usr/local/go/src/text/template/exec.go:422 +0x126
text/template.(*state).walk(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0x117c440, 0xc000088870)
	/usr/local/go/src/text/template/exec.go:247 +0x4a0
text/template.(*state).walk(0xc000055e28, 0x11396a0, 0xc0000900a0, 0x99, 0x117c6c0, 0xc0000886f0)
	/usr/local/go/src/text/template/exec.go:255 +0x118
text/template.(*Template).execute(0xc00009a080, 0x117bdc0, 0xc0000a0008, 0x11396a0, 0xc0000900a0, 0x0, 0x0)
	/usr/local/go/src/text/template/exec.go:210 +0x1e9
text/template.(*Template).Execute(0xc00009a080, 0x117bdc0, 0xc0000a0008, 0x11396a0, 0xc0000900a0, 0xc0000900a0, 0xc0000900a0)
	/usr/local/go/src/text/template/exec.go:193 +0x53
html/template.(*Template).Execute(0xc000088690, 0x117bdc0, 0xc0000a0008, 0x11396a0, 0xc0000900a0, 0x0, 0x0)
	/usr/local/go/src/html/template/template.go:122 +0x8c
main.main()
	/tmp/template.go:17 +0xfa
exit status 2
@robpike
Copy link
Contributor

robpike commented Apr 6, 2018

This is html/template-specific. With text/template, it generates:

<script><nil>+<no value></script>

as expected (in fact, better than expected).

@robpike robpike changed the title text/template: panic when calling function with untyped nil html/template: panic when calling function with untyped nil Apr 6, 2018
@bcmills bcmills added this to the Go1.11 milestone Apr 6, 2018
@bcmills bcmills added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Apr 6, 2018
@odeke-em
Copy link
Member

/cc @mvdan

@mvdan mvdan self-assigned this Apr 25, 2018
@mvdan
Copy link
Member

mvdan commented Apr 25, 2018

Thanks @odeke-em for the ping. I had seen this issue, but I had not realised it was directly connected to my other fix. I believe I know what the simple solution here is.

@mvdan
Copy link
Member

mvdan commented Apr 25, 2018

@robpike the reason that text/template does a better job at discerning the two kinds of nil is because of https://go-review.googlesource.com/c/go/+/95215. I'm sure it was also behaving in a confusing way before that CL.

@gopherbot
Copy link

Change https://golang.org/cl/109215 mentions this issue: html/template: always write untyped nil as JS null

@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 May 8, 2018
@golang golang locked and limited conversation to collaborators May 9, 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

6 participants