Skip to content

Commit

Permalink
cmd/compile, runtime: fix pedantic int->string conversions
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
mdempsky committed Mar 31, 2016
1 parent e7538df commit e606671
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/cmd/compile/internal/gc/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
3 changes: 3 additions & 0 deletions src/runtime/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
Expand Down
25 changes: 25 additions & 0 deletions test/fixedbugs/issue15039.go
Original file line number Diff line number Diff line change
@@ -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")
}
}

0 comments on commit e606671

Please sign in to comment.