Commit 8801bdf2 authored by Aamir Khan's avatar Aamir Khan Committed by Rob Pike

text/template: template must be initialized at the time of creation

t.init() should be called at the time of template creation
i.e, template.New() and t.New() instead of later in the process.

- Removed calls of t.init() from t.Parse(), t.Execute(), t.Funcs()
- Also got rid of t.common != nil checks as it should never be nil

Fixes #10879

Change-Id: I1b7ac812f02c841ae80037babce7e2b0a2df13e8
Reviewed-on: https://go-review.googlesource.com/10240Reviewed-by: default avatarRob Pike <r@golang.org>
parent bc8e1293
...@@ -134,7 +134,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { ...@@ -134,7 +134,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
wr: wr, wr: wr,
vars: []variable{{"$", value}}, vars: []variable{{"$", value}},
} }
t.init()
if t.Tree == nil || t.Root == nil { if t.Tree == nil || t.Root == nil {
state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates()) state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
} }
...@@ -147,9 +146,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { ...@@ -147,9 +146,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
// it returns the empty string. For generating an error message here // it returns the empty string. For generating an error message here
// and in html/template. // and in html/template.
func (t *Template) DefinedTemplates() string { func (t *Template) DefinedTemplates() string {
if t.common == nil {
return ""
}
var b bytes.Buffer var b bytes.Buffer
for name, tmpl := range t.tmpl { for name, tmpl := range t.tmpl {
if tmpl.Tree == nil || tmpl.Root == nil { if tmpl.Tree == nil || tmpl.Root == nil {
......
...@@ -290,3 +290,9 @@ func TestRedefinition(t *testing.T) { ...@@ -290,3 +290,9 @@ func TestRedefinition(t *testing.T) {
t.Fatalf("expected redefinition error; got %v", err) t.Fatalf("expected redefinition error; got %v", err)
} }
} }
// Issue 10879
func TestEmptyTemplateCloneCrash(t *testing.T) {
t1 := New("base")
t1.Clone() // used to panic
}
...@@ -36,9 +36,11 @@ type Template struct { ...@@ -36,9 +36,11 @@ type Template struct {
// New allocates a new template with the given name. // New allocates a new template with the given name.
func New(name string) *Template { func New(name string) *Template {
return &Template{ t := &Template{
name: name, name: name,
} }
t.init()
return t
} }
// Name returns the name of the template. // Name returns the name of the template.
...@@ -50,13 +52,14 @@ func (t *Template) Name() string { ...@@ -50,13 +52,14 @@ func (t *Template) Name() string {
// delimiters. The association, which is transitive, allows one template to // delimiters. The association, which is transitive, allows one template to
// invoke another with a {{template}} action. // invoke another with a {{template}} action.
func (t *Template) New(name string) *Template { func (t *Template) New(name string) *Template {
t.init() nt := &Template{
return &Template{
name: name, name: name,
common: t.common, common: t.common,
leftDelim: t.leftDelim, leftDelim: t.leftDelim,
rightDelim: t.rightDelim, rightDelim: t.rightDelim,
} }
nt.init()
return nt
} }
func (t *Template) init() { func (t *Template) init() {
...@@ -110,7 +113,7 @@ func (t *Template) copy(c *common) *Template { ...@@ -110,7 +113,7 @@ func (t *Template) copy(c *common) *Template {
// AddParseTree creates a new template with the name and parse tree // AddParseTree creates a new template with the name and parse tree
// and associates it with t. // and associates it with t.
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
if t.common != nil && t.tmpl[name] != nil { if t.tmpl[name] != nil {
return nil, fmt.Errorf("template: redefinition of template %q", name) return nil, fmt.Errorf("template: redefinition of template %q", name)
} }
nt := t.New(name) nt := t.New(name)
...@@ -122,9 +125,6 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error ...@@ -122,9 +125,6 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error
// Templates returns a slice of the templates associated with t, including t // Templates returns a slice of the templates associated with t, including t
// itself. // itself.
func (t *Template) Templates() []*Template { func (t *Template) Templates() []*Template {
if t.common == nil {
return nil
}
// Return a slice so we don't expose the map. // Return a slice so we don't expose the map.
m := make([]*Template, 0, len(t.tmpl)) m := make([]*Template, 0, len(t.tmpl))
for _, v := range t.tmpl { for _, v := range t.tmpl {
...@@ -149,7 +149,6 @@ func (t *Template) Delims(left, right string) *Template { ...@@ -149,7 +149,6 @@ func (t *Template) Delims(left, right string) *Template {
// type. However, it is legal to overwrite elements of the map. The return // type. However, it is legal to overwrite elements of the map. The return
// value is the template, so calls can be chained. // value is the template, so calls can be chained.
func (t *Template) Funcs(funcMap FuncMap) *Template { func (t *Template) Funcs(funcMap FuncMap) *Template {
t.init()
t.muFuncs.Lock() t.muFuncs.Lock()
defer t.muFuncs.Unlock() defer t.muFuncs.Unlock()
addValueFuncs(t.execFuncs, funcMap) addValueFuncs(t.execFuncs, funcMap)
...@@ -160,9 +159,6 @@ func (t *Template) Funcs(funcMap FuncMap) *Template { ...@@ -160,9 +159,6 @@ func (t *Template) Funcs(funcMap FuncMap) *Template {
// Lookup returns the template with the given name that is associated with t, // Lookup returns the template with the given name that is associated with t,
// or nil if there is no such template. // or nil if there is no such template.
func (t *Template) Lookup(name string) *Template { func (t *Template) Lookup(name string) *Template {
if t.common == nil {
return nil
}
return t.tmpl[name] return t.tmpl[name]
} }
...@@ -174,7 +170,6 @@ func (t *Template) Lookup(name string) *Template { ...@@ -174,7 +170,6 @@ func (t *Template) Lookup(name string) *Template {
// (In multiple calls to Parse with the same receiver template, only one call // (In multiple calls to Parse with the same receiver template, only one call
// can contain text other than space, comments, and template definitions.) // can contain text other than space, comments, and template definitions.)
func (t *Template) Parse(text string) (*Template, error) { func (t *Template) Parse(text string) (*Template, error) {
t.init()
t.muFuncs.RLock() t.muFuncs.RLock()
trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins) trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
t.muFuncs.RUnlock() t.muFuncs.RUnlock()
......
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