From: Daniel Martí Date: Tue, 24 Sep 2019 12:11:36 +0000 (+0100) Subject: text/template: don't evaluate '.' as a float64 X-Git-Tag: go1.14beta1~987 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0f7b4e72a054f974489d8342cdae5a6a7ba7a31b;p=gostls13.git text/template: don't evaluate '.' as a float64 When using a '.' constant literal as a reflect.Value variadic argument, idealConstant would incorrectly result in a float64. This is because rune literals can be represented as a float64, and contain a period, which tricked the logic into thinking the literal must have been a floating point number. This also happened with other characters that can be part of a floating point number, such as 'e' or 'P'. To fix these edge cases, exit the case sooner if the literal was a rune, since that should always go to the int case instead. Finally, add test cases that verify that they behave properly. These would error before, since eq would receive a mix of int and float64, which aren't comparable. Fixes #34483. Change-Id: Icfcb7803bfa0cf317a1d1adacacad3d69a57eb42 Reviewed-on: https://go-review.googlesource.com/c/go/+/196808 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Tom Payne Reviewed-by: Rob Pike --- diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 97c9d1f574..f9bc5d980c 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -496,20 +496,29 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { switch { case constant.IsComplex: return reflect.ValueOf(constant.Complex128) // incontrovertible. - case constant.IsFloat && !isHexInt(constant.Text) && strings.ContainsAny(constant.Text, ".eEpP"): + + case constant.IsFloat && + !isHexInt(constant.Text) && !isRuneInt(constant.Text) && + strings.ContainsAny(constant.Text, ".eEpP"): return reflect.ValueOf(constant.Float64) + case constant.IsInt: n := int(constant.Int64) if int64(n) != constant.Int64 { s.errorf("%s overflows int", constant.Text) } return reflect.ValueOf(n) + case constant.IsUint: s.errorf("%s overflows int", constant.Text) } return zero } +func isRuneInt(s string) bool { + return len(s) > 0 && s[0] == '\'' +} + func isHexInt(s string) bool { return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && !strings.ContainsAny(s, "pP") } diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 7f2305ace0..f24a59e549 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -663,6 +663,12 @@ var execTests = []execTest{ {"bug17c", "{{len .NonEmptyInterfacePtS}}", "2", tVal, true}, {"bug17d", "{{index .NonEmptyInterfacePtS 0}}", "a", tVal, true}, {"bug17e", "{{range .NonEmptyInterfacePtS}}-{{.}}-{{end}}", "-a--b-", tVal, true}, + + // More variadic function corner cases. Some runes would get evaluated + // as constant floats instead of ints. Issue 34483. + {"bug18a", "{{eq . '.'}}", "true", '.', true}, + {"bug18b", "{{eq . 'e'}}", "true", 'e', true}, + {"bug18c", "{{eq . 'P'}}", "true", 'P', true}, } func zeroArgs() string {