]> Cypherpunks repositories - gostls13.git/commitdiff
fmt: rely on utf8.AppendRune
authorJoe Tsai <joetsai@digital-static.net>
Thu, 16 Jun 2022 00:29:25 +0000 (17:29 -0700)
committerGopher Robot <gobot@golang.org>
Wed, 21 Sep 2022 13:54:31 +0000 (13:54 +0000)
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 <joetsai@digital-static.net>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>

src/fmt/fmt_test.go
src/fmt/format.go
src/fmt/print.go

index d2fa81a7b337da953ad4e97fb56e5e12e35dfc0f..37d82acbf420dd09023abb6c2bb0f57774be5641 100644 (file)
@@ -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"},
index bd00e5a5e0131f071d9b3b0a5f6c8d2b6ad1060b..617f78f15ea2b0b71a80f39bbb4cad066c6b9289 100644 (file)
@@ -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.
index 8082d1387417c292de14939b7af3dfa1f8fb614e..4eabda1ce862c2ddcf1e264a773bcb9e26d6368d 100644 (file)
@@ -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.