Previously, cmd/compile rejected constant int->string conversions if
the integer value did not fit into an "int" value. Also, runtime
incorrectly truncated 64-bit values to 32-bit before checking if
they're a valid Unicode code point. According to the Go spec, both of
these cases should instead yield "\uFFFD".
Fixes #15039.
Change-Id: I3c8a3ad9a0780c0a8dc1911386a523800fec9764
Reviewed-on: https://go-review.googlesource.com/21344
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
func tostr(v Val) Val {
switch v.Ctype() {
case CTINT, CTRUNE:
- if v.U.(*Mpint).Cmp(Minintval[TINT]) < 0 || v.U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
- Yyerror("overflow in int -> string")
+ var i int64 = 0xFFFD
+ if u := v.U.(*Mpint); u.Cmp(Minintval[TUINT32]) >= 0 && u.Cmp(Maxintval[TUINT32]) <= 0 {
+ i = u.Int64()
}
- r := uint(v.U.(*Mpint).Int64())
v = Val{}
- v.U = string(r)
+ v.U = string(i)
case CTFLT:
Yyerror("no float -> string")
} else {
s, b = rawstring(4)
}
+ if int64(rune(v)) != v {
+ v = runeerror
+ }
n := runetochar(b, rune(v))
return s[:n]
}
--- /dev/null
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ const fffd = "\uFFFD"
+
+ // runtime.intstring used to convert int64 to rune without checking
+ // for truncation.
+ u := uint64(0x10001f4a9)
+ big := string(u)
+ if big != fffd {
+ panic("big != bad")
+ }
+
+ // cmd/compile used to require integer constants to fit into an "int".
+ const huge = string(1<<100)
+ if huge != fffd {
+ panic("huge != bad")
+ }
+}