diff options
| -rw-r--r-- | src/runtime/export_test.go | 18 | ||||
| -rw-r--r-- | src/runtime/print.go | 20 | ||||
| -rw-r--r-- | src/runtime/print_test.go | 65 |
3 files changed, 99 insertions, 4 deletions
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 4f6ef9a3f2..95e2cbb959 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -2079,3 +2079,21 @@ func DumpPrintQuoted(s string) string { return string(buf) } + +// DumpPrint returns the output of print(v). +func DumpPrint[T any](v T) string { + gp := getg() + gp.writebuf = make([]byte, 0, 2048) + print(v) + buf := gp.writebuf + gp.writebuf = nil + + return string(buf) +} + +var ( + Float64Bytes = float64Bytes + Float32Bytes = float32Bytes + Complex128Bytes = complex128Bytes + Complex64Bytes = complex64Bytes +) diff --git a/src/runtime/print.go b/src/runtime/print.go index 5d1bc22809..d65e457a03 100644 --- a/src/runtime/print.go +++ b/src/runtime/print.go @@ -122,23 +122,35 @@ func printbool(v bool) { } } +// float64 requires 1+17+1+1+1+3 = 24 bytes max (sign+digits+decimal point+e+sign+exponent digits). +const float64Bytes = 24 + func printfloat64(v float64) { - var buf [20]byte + var buf [float64Bytes]byte gwrite(strconv.AppendFloat(buf[:0], v, 'g', -1, 64)) } +// float32 requires 1+9+1+1+1+2 = 15 bytes max (sign+digits+decimal point+e+sign+exponent digits). +const float32Bytes = 15 + func printfloat32(v float32) { - var buf [20]byte + var buf [float32Bytes]byte gwrite(strconv.AppendFloat(buf[:0], float64(v), 'g', -1, 32)) } +// complex128 requires 24+24+1+1+1 = 51 bytes max (paren+float64+float64+i+paren). +const complex128Bytes = 2*float64Bytes + 3 + func printcomplex128(c complex128) { - var buf [44]byte + var buf [complex128Bytes]byte gwrite(strconv.AppendComplex(buf[:0], c, 'g', -1, 128)) } +// complex64 requires 15+15+1+1+1 = 33 bytes max (paren+float32+float32+i+paren). +const complex64Bytes = 2*float32Bytes + 3 + func printcomplex64(c complex64) { - var buf [44]byte + var buf [complex64Bytes]byte gwrite(strconv.AppendComplex(buf[:0], complex128(c), 'g', -1, 64)) } diff --git a/src/runtime/print_test.go b/src/runtime/print_test.go new file mode 100644 index 0000000000..cfc27ed95b --- /dev/null +++ b/src/runtime/print_test.go @@ -0,0 +1,65 @@ +// Copyright 2026 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 runtime_test + +import ( + "math" + "runtime" + "testing" +) + +func FuzzPrintFloat64(f *testing.F) { + f.Add(math.SmallestNonzeroFloat64) + f.Add(math.MaxFloat64) + f.Add(-1.7976931348623157e+308) // requires 24 digits + + f.Fuzz(func(t *testing.T, v float64) { + s := runtime.DumpPrint(v) + if len(s) > runtime.Float64Bytes { + t.Errorf("print(%f) got %s (len %d) want len <= %d", v, s, len(s), runtime.Float64Bytes) + } + }) +} + +func FuzzPrintFloat32(f *testing.F) { + f.Add(float32(math.SmallestNonzeroFloat32)) + f.Add(float32(math.MaxFloat32)) + f.Add(float32(-1.06338233e+37)) // requires 15 digits + + f.Fuzz(func(t *testing.T, v float32) { + s := runtime.DumpPrint(v) + if len(s) > runtime.Float32Bytes { + t.Errorf("print(%f) got %s (len %d) want len <= %d", v, s, len(s), runtime.Float32Bytes) + } + }) +} + +func FuzzPrintComplex128(f *testing.F) { + f.Add(math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64) + f.Add(math.MaxFloat64, math.MaxFloat64) + f.Add(-1.7976931348623157e+308, -1.7976931348623157e+308) // requires 51 digits + + f.Fuzz(func(t *testing.T, r, i float64) { + v := complex(r, i) + s := runtime.DumpPrint(v) + if len(s) > runtime.Complex128Bytes { + t.Errorf("print(%f) got %s (len %d) want len <= %d", v, s, len(s), runtime.Complex128Bytes) + } + }) +} + +func FuzzPrintComplex64(f *testing.F) { + f.Add(float32(math.SmallestNonzeroFloat32), float32(math.SmallestNonzeroFloat32)) + f.Add(float32(math.MaxFloat32), float32(math.MaxFloat32)) + f.Add(float32(-1.06338233e+37), float32(-1.06338233e+37)) // requires 33 digits + + f.Fuzz(func(t *testing.T, r, i float32) { + v := complex(r, i) + s := runtime.DumpPrint(v) + if len(s) > runtime.Complex64Bytes { + t.Errorf("print(%f) got %s (len %d) want len <= %d", v, s, len(s), runtime.Complex64Bytes) + } + }) +} |
