]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: fix variadic function call corner case
authorDidier Spezia <didier.06@gmail.com>
Wed, 27 May 2015 11:44:19 +0000 (11:44 +0000)
committerRob Pike <r@golang.org>
Mon, 1 Jun 2015 22:06:40 +0000 (22:06 +0000)
Executing a template involving variadic functions featuring
a []interface{} slice (such as printf) could result in a
panic in reflect.Value.Call, due to incorrect type checking.

The following expressions failed (with a panic):
{{true|printf}}
{{1|printf}}
{{1.1|printf}}
{{'x'|printf}}
{{1+2i|printf}}

Implemented proper type checks for the fixed parameters of the
variadic functions.

Fixes #10946

Change-Id: Ia75333f651f73b3d2e024cb0c47cc30d90cb6852
Reviewed-on: https://go-review.googlesource.com/10403
Reviewed-by: Rob Pike <r@golang.org>
src/text/template/exec.go
src/text/template/exec_test.go

index b4e6cc8282b0eb7ee8913d5511f5f24feb435f65..8e9edcfbe99951ddb4ce499b1a3e1094c322a2c9 100644 (file)
@@ -581,7 +581,15 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
        if final.IsValid() {
                t := typ.In(typ.NumIn() - 1)
                if typ.IsVariadic() {
-                       t = t.Elem()
+                       if numIn-1 < numFixed {
+                               // The added final argument corresponds to a fixed parameter of the function.
+                               // Validate against the type of the actual parameter.
+                               t = typ.In(numIn - 1)
+                       } else {
+                               // The added final argument corresponds to the variadic part.
+                               // Validate against the type of the elements of the variadic slice.
+                               t = t.Elem()
+                       }
                }
                argv[i] = s.validateType(final, t)
        }
index 0f1ad62380af4c911a0d9547584fb4851afb1d98..f083547ed8db79198f56c3d887dd1d68347a039d 100644 (file)
@@ -533,6 +533,18 @@ var execTests = []execTest{
        {"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
        // Didn't call validateType on function results. Issue 10800.
        {"bug15", "{{valueString returnInt}}", "", tVal, false},
+       // Variadic function corner cases. Issue 10946.
+       {"bug16a", "{{true|printf}}", "", tVal, false},
+       {"bug16b", "{{1|printf}}", "", tVal, false},
+       {"bug16c", "{{1.1|printf}}", "", tVal, false},
+       {"bug16d", "{{'x'|printf}}", "", tVal, false},
+       {"bug16e", "{{0i|printf}}", "", tVal, false},
+       {"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false},
+       {"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true},
+       {"bug16h", "{{1|oneArg}}", "", tVal, false},
+       {"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
+       {"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
+       {"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
 }
 
 func zeroArgs() string {
@@ -543,6 +555,10 @@ func oneArg(a string) string {
        return "oneArg=" + a
 }
 
+func twoArgs(a, b string) string {
+       return "twoArgs=" + a + b
+}
+
 func dddArg(a int, b ...string) string {
        return fmt.Sprintln(a, b)
 }
@@ -620,6 +636,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
                "oneArg":      oneArg,
                "returnInt":   returnInt,
                "stringer":    stringer,
+               "twoArgs":     twoArgs,
                "typeOf":      typeOf,
                "valueString": valueString,
                "vfunc":       vfunc,