cmd/compile, runtime: fix pedantic int->string conversions

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>
This commit is contained in:
Matthew Dempsky 2016-03-31 02:04:12 -07:00
parent e7538df701
commit e6066711a0
3 changed files with 32 additions and 4 deletions

View file

@ -468,12 +468,12 @@ func overflow(v Val, t *Type) {
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")

View file

@ -236,6 +236,9 @@ func intstring(buf *[4]byte, v int64) string {
} else {
s, b = rawstring(4)
}
if int64(rune(v)) != v {
v = runeerror
}
n := runetochar(b, rune(v))
return s[:n]
}

View file

@ -0,0 +1,25 @@
// 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")
}
}