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: "no such template" error after use of Clone #17735

Closed
rhysh opened this issue Nov 2, 2016 · 6 comments
Closed

html/template: "no such template" error after use of Clone #17735

rhysh opened this issue Nov 2, 2016 · 6 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 Nov 2, 2016

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

$ go version
go version devel +3be166d Tue Nov 1 22:44:31 2016 +0000 darwin/amd64

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

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/rhys/work"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/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/49/zmds5zsn75z1283vtzxyfr5hj7yjq4/T/go-build002017019=/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?

I have an application that sets up and executes some templates. The program starts with a New template, sets a FuncMap via Funcs, and then it calls Parse with a base template. The text of the base template uses the template keyword to invoke some templates—it also uses the define keyword to specify default implementations of the templates it invokes.

Then the program calls Clone on that template a few separate times, calls Parse with template text that includes re-definitions of the templates invoked by the base template, and then calls Execute on the resulting template.Template values.

What did you expect to see?

With go1.7.3, the program executes its templates successfully.

What did you see instead?

With go version devel +3be166d Tue Nov 1 22:44:31 2016 +0000, executing the template fails with

no such template "title$htmltemplate_stateRCDATA_elementTitle"

The text of the template includes {{ define "title" }}{{ end }} and {{ template "title" . }}.

I've bisected this to cd2c9df, html/template: fix Clone so that t.Lookup(t.Name()) yields t.

I can work around the bug by inserting a layer of t = template.Must(t.New("foo").Parse("")) right before the call to Clone.

I haven't been able to reduce this to a minimal test case. Below is code that does not reproduce the bug, but is similar in shape to what the application does.

package main

import (
	"fmt"
	"html/template"
	"log"
	"os"
)

func main() {
	log.SetFlags(0)

	base := `
{{ define "base" -}}
	{{ template "title" . -}}
{{ end -}}

{{ define "title" }}{{ end -}}
`[1:]

	page := `
{{ template "base" . }}
{{ define "title" }}OK{{ end -}}
`[1:]

	t1 := template.New("")
	t1 = t1.Funcs(template.FuncMap{})
	t1 = template.Must(t1.New("base").Parse(base))

	for i := 0; i < 10; i++ {
		t2 := template.Must(t1.Clone())
		t2 = template.Must(t2.New(fmt.Sprintf("%d", i)).Parse(page))

		err := t2.Execute(os.Stdout, nil)
		if err != nil {
			log.Fatalf("err=%q")
		}
	}
}
@cespare
Copy link
Contributor

cespare commented Nov 2, 2016

@rhysh I'm happy to poke around, since that's my commit. Bit hard without a repro, though.

@rhysh
Copy link
Contributor Author

rhysh commented Nov 2, 2016

Thanks @cespare . I agree that not much can be done without a repro, and unfortunately I'm not able to share the application code. Maybe someone else will encounter the issue and be able to extend the report...

There is a place within html/template where a template's name can be overwritten, in escaper.commit. I've found that code path is involved when the bug triggers:

n.Name = name

It seems like there are parts of html/template that assume that the templates they can access are not accessible by external code. The change to Clone's behavior seems to have disrupted that implicit invariant.

@rhysh
Copy link
Contributor Author

rhysh commented Nov 3, 2016

I've got a reproducer now, @cespare !

Critical to the failure is that the template named "title" is invoked within an html title element.

$ go run ./main.go 
<title>OK</title>

err="html/template:base:2:20: no such template \"title$htmltemplate_stateRCDATA_elementTitle\""
exit status 1
$ go version
go version devel +3be166d Tue Nov 1 22:44:31 2016 +0000 darwin/amd64
package main

import (
    "fmt"
    "html/template"
    "log"
    "os"
)

func main() {
    log.SetFlags(0)

    base := `
{{ define "base" -}}
    <title>{{ template "title" . -}}</title>
{{ end -}}

{{ define "title" }}{{ end -}}
`[1:]

    page := `
{{ template "base" . }}
{{ define "title" }}OK{{ end -}}
`[1:]

    t1 := template.New("")
    t1 = t1.Funcs(template.FuncMap{})
    t1 = template.Must(t1.New("base").Parse(base))

    for i := 0; i < 2; i++ {
        t2 := template.Must(t1.Clone())
        t2 = template.Must(t2.New(fmt.Sprintf("%d", i)).Parse(page))

        err := t2.Execute(os.Stdout, nil)
        if err != nil {
            log.Fatalf("err=%q", err)
        }
    }
}

@dsnet dsnet added this to the Go1.8 milestone Nov 3, 2016
@dsnet
Copy link
Member

dsnet commented Nov 3, 2016

Thanks for filing these. I've been seeing some template related bugs in a different regression test and haven't had time to make a smaller reproduction.

@cespare
Copy link
Contributor

cespare commented Nov 7, 2016

Thanks @rhysh. I'm going to try to look at this today. It sounds as though my patch for #16101 broke one implicit assumption while fixing another.

@quentinmit quentinmit added the NeedsFix The path to resolution is known, but the work has not been done. label Nov 7, 2016
@gopherbot
Copy link

CL https://golang.org/cl/33210 mentions this issue.

@golang golang locked and limited conversation to collaborators Nov 15, 2017
@rsc rsc unassigned cespare 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