diff options
Diffstat (limited to 'src/pkg/text/template')
-rw-r--r-- | src/pkg/text/template/doc.go | 2 | ||||
-rw-r--r-- | src/pkg/text/template/exec.go | 11 | ||||
-rw-r--r-- | src/pkg/text/template/exec_test.go | 30 | ||||
-rw-r--r-- | src/pkg/text/template/multi_test.go | 12 | ||||
-rw-r--r-- | src/pkg/text/template/template.go | 2 |
5 files changed, 44 insertions, 13 deletions
diff --git a/src/pkg/text/template/doc.go b/src/pkg/text/template/doc.go index f622ac7dc..7c6efd59c 100644 --- a/src/pkg/text/template/doc.go +++ b/src/pkg/text/template/doc.go @@ -20,7 +20,7 @@ The input text for a template is UTF-8-encoded text in any format. "{{" and "}}"; all text outside actions is copied to the output unchanged. Actions may not span newlines, although comments can. -Once constructed, a template may be executed safely in parallel. +Once parsed, a template may be executed safely in parallel. Here is a trivial example that prints "17 items are made of wool". diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go index 43b0b266e..2f3231264 100644 --- a/src/pkg/text/template/exec.go +++ b/src/pkg/text/template/exec.go @@ -108,6 +108,10 @@ func errRecover(errp *error) { // ExecuteTemplate applies the template associated with t that has the given name // to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { tmpl := t.tmpl[name] if tmpl == nil { @@ -118,6 +122,10 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) // Execute applies a parsed template to the specified data object, // and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { defer errRecover(&err) value := reflect.ValueOf(data) @@ -594,6 +602,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu switch { case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ): value = value.Elem() + if !value.IsValid() { + s.errorf("dereference of nil pointer of type %s", typ) + } case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr(): value = value.Addr() default: diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go index f60702de8..868f2cb94 100644 --- a/src/pkg/text/template/exec_test.go +++ b/src/pkg/text/template/exec_test.go @@ -512,6 +512,8 @@ var execTests = []execTest{ {"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true}, // Field chain starting with function did not work. {"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true}, + // Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333. + {"bug11", "{{valueString .PS}}", "", T{}, false}, } func zeroArgs() string { @@ -546,6 +548,11 @@ func vfunc(V, *V) string { return "vfunc" } +// valueString takes a string, not a pointer. +func valueString(v string) string { + return "value is ignored" +} + func add(args ...int) int { sum := 0 for _, x := range args { @@ -580,17 +587,18 @@ func mapOfThree() interface{} { func testExecute(execTests []execTest, template *Template, t *testing.T) { b := new(bytes.Buffer) funcs := FuncMap{ - "add": add, - "count": count, - "dddArg": dddArg, - "echo": echo, - "makemap": makemap, - "mapOfThree": mapOfThree, - "oneArg": oneArg, - "stringer": stringer, - "typeOf": typeOf, - "vfunc": vfunc, - "zeroArgs": zeroArgs, + "add": add, + "count": count, + "dddArg": dddArg, + "echo": echo, + "makemap": makemap, + "mapOfThree": mapOfThree, + "oneArg": oneArg, + "stringer": stringer, + "typeOf": typeOf, + "valueString": valueString, + "vfunc": vfunc, + "zeroArgs": zeroArgs, } for _, test := range execTests { var tmpl *Template diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go index 1f6ed5d8e..e4e804880 100644 --- a/src/pkg/text/template/multi_test.go +++ b/src/pkg/text/template/multi_test.go @@ -259,6 +259,18 @@ func TestAddParseTree(t *testing.T) { } } +// Issue 7032 +func TestAddParseTreeToUnparsedTemplate(t *testing.T) { + master := "{{define \"master\"}}{{end}}" + tmpl := New("master") + tree, err := parse.Parse("master", master, "", "", nil) + if err != nil { + t.Fatalf("unexpected parse err: %v", err) + } + masterTree := tree["master"] + tmpl.AddParseTree("master", masterTree) // used to panic +} + func TestRedefinition(t *testing.T) { var tmpl *Template var err error diff --git a/src/pkg/text/template/template.go b/src/pkg/text/template/template.go index a2b9062ad..249d0cbfb 100644 --- a/src/pkg/text/template/template.go +++ b/src/pkg/text/template/template.go @@ -105,7 +105,7 @@ func (t *Template) copy(c *common) *Template { // AddParseTree creates a new template with the name and parse tree // and associates it with t. func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { - if t.tmpl[name] != nil { + if t.common != nil && t.tmpl[name] != nil { return nil, fmt.Errorf("template: redefinition of template %q", name) } nt := t.New(name) |