]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: don't evaluate '.' as a float64
authorDaniel Martí <mvdan@mvdan.cc>
Tue, 24 Sep 2019 12:11:36 +0000 (13:11 +0100)
committerDaniel Martí <mvdan@mvdan.cc>
Wed, 25 Sep 2019 09:22:38 +0000 (09:22 +0000)
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í <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tom Payne <tom@airmap.com>
Reviewed-by: Rob Pike <r@golang.org>
src/text/template/exec.go
src/text/template/exec_test.go

index 97c9d1f5748ce1e5b583f7c224d9e0b444cd0b6c..f9bc5d980c8c53e0e1f47cb421bd6ad86ad92dd1 100644 (file)
@@ -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")
 }
index 7f2305ace00b468d9a77c3ef2ab8c0d989c3fd94..f24a59e5495d81f38a6633b62d27698dac633db2 100644 (file)
@@ -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 {