From: Joe Tsai Date: Thu, 16 Jun 2022 00:29:25 +0000 (-0700) Subject: fmt: rely on utf8.AppendRune X-Git-Tag: go1.20rc1~971 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9c916c79011f3af98b5670eb2ba55349ba904522;p=gostls13.git fmt: rely on utf8.AppendRune This is both simpler and more performant. The need for fmt.fmtC to manually check for utf8.MaxRune is subtle to avoid overflow when converting uint64 to rune, so a test case was added to exercise this edge case. Change-Id: I0f2e6cce91dcd4cc6b88190c29807ca1c58e999d Reviewed-on: https://go-review.googlesource.com/c/go/+/412335 Auto-Submit: Joseph Tsai Auto-Submit: Robert Griesemer Run-TryBot: Joseph Tsai Reviewed-by: Cherry Mui TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer --- diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index d2fa81a7b3..37d82acbf4 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -249,6 +249,7 @@ var fmtTests = []struct { {"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect. {"%3c", '⌘', " ⌘"}, {"%-3c", '⌘', "⌘ "}, + {"%c", uint64(0x100000000), "\ufffd"}, // Runes that are not printable. {"%c", '\U00000e00', "\u0e00"}, {"%c", '\U0010ffff', "\U0010ffff"}, diff --git a/src/fmt/format.go b/src/fmt/format.go index bd00e5a5e0..617f78f15e 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -461,13 +461,14 @@ func (f *fmt) fmtQ(s string) { // fmtC formats an integer as a Unicode character. // If the character is not valid Unicode, it will print '\ufffd'. func (f *fmt) fmtC(c uint64) { + // Explicitly check whether c exceeds utf8.MaxRune since the conversion + // of a uint64 to a rune may lose precision that indicates an overflow. r := rune(c) if c > utf8.MaxRune { r = utf8.RuneError } buf := f.intbuf[:0] - w := utf8.EncodeRune(buf[:utf8.UTFMax], r) - f.pad(buf[:w]) + f.pad(utf8.AppendRune(buf, r)) } // fmtQc formats an integer as a single-quoted, escaped Go character constant. diff --git a/src/fmt/print.go b/src/fmt/print.go index 8082d13874..4eabda1ce8 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -113,18 +113,7 @@ func (b *buffer) writeByte(c byte) { } func (bp *buffer) writeRune(r rune) { - if r < utf8.RuneSelf { - *bp = append(*bp, byte(r)) - return - } - - b := *bp - n := len(b) - for n+utf8.UTFMax > cap(b) { - b = append(b, 0) - } - w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r) - *bp = b[:n+w] + *bp = utf8.AppendRune(*bp, r) } // pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.