From 5c60a4fb0a7f49105e2daa10efe45faf2bf3a36b Mon Sep 17 00:00:00 2001 From: Didier Spezia Date: Wed, 27 May 2015 11:44:19 +0000 Subject: [PATCH] text/template: fix variadic function call corner case 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 --- src/text/template/exec.go | 10 +++++++++- src/text/template/exec_test.go | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index b4e6cc8282..8e9edcfbe9 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -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) } diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 0f1ad62380..f083547ed8 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -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,