reflect: fix (u)int -> string conversions for invalid code points

This commit is contained in:
Damian Gryski
2026-05-26 14:28:08 -07:00
committed by Damian Gryski
parent e111b489ec
commit 364ac2dcb2
3 changed files with 96 additions and 7 deletions
+13 -6
View File
@@ -1690,20 +1690,27 @@ func makeComplex(flags valueFlags, f complex128, t *RawType) Value {
func stringFromUnicode(x rune) string
func cvtIntString(v Value, t *RawType) Value {
b := stringFromUnicode(rune(v.Int()))
s := "\uFFFD"
if x := v.Int(); int64(rune(x)) == x {
s = string(rune(x))
}
return Value{
typecode: t,
value: unsafe.Pointer(&b),
flags: v.flags,
value: unsafe.Pointer(&s),
flags: v.flags | valueFlagRO,
}
}
func cvtUintString(v Value, t *RawType) Value {
b := stringFromUnicode(rune(v.Uint()))
s := "\uFFFD"
if x := v.Uint(); uint64(rune(x)) == x {
s = string(rune(x))
}
return Value{
typecode: t,
value: unsafe.Pointer(&b),
flags: v.flags,
value: unsafe.Pointer(&s),
flags: v.flags | valueFlagRO,
}
}
+80
View File
@@ -189,6 +189,86 @@ func TestTinyConvert(t *testing.T) {
{V(complex64(2i)), V(complex128(2i))},
{V(complex128(3i)), V(complex64(3i))},
{V(complex128(4i)), V(complex128(4i))},
// string
{V(string("hello")), V(string("hello"))},
{V(string("bytes1")), V([]byte("bytes1"))},
{V([]byte("bytes2")), V(string("bytes2"))},
{V([]byte("bytes3")), V([]byte("bytes3"))},
{V(string("runes♝")), V([]rune("runes♝"))},
{V([]rune("runes♕")), V(string("runes♕"))},
{V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))},
{V(int('a')), V(string("a"))},
{V(int8('a')), V(string("a"))},
{V(int16('a')), V(string("a"))},
{V(int32('a')), V(string("a"))},
{V(int64('a')), V(string("a"))},
{V(uint('a')), V(string("a"))},
{V(uint8('a')), V(string("a"))},
{V(uint16('a')), V(string("a"))},
{V(uint32('a')), V(string("a"))},
{V(uint64('a')), V(string("a"))},
{V(uintptr('a')), V(string("a"))},
{V(int(-1)), V(string("\uFFFD"))},
{V(int8(-2)), V(string("\uFFFD"))},
{V(int16(-3)), V(string("\uFFFD"))},
{V(int32(-4)), V(string("\uFFFD"))},
{V(int64(-5)), V(string("\uFFFD"))},
{V(int64(-1 << 32)), V(string("\uFFFD"))},
{V(int64(1 << 32)), V(string("\uFFFD"))},
{V(uint(0x110001)), V(string("\uFFFD"))},
{V(uint32(0x110002)), V(string("\uFFFD"))},
{V(uint64(0x110003)), V(string("\uFFFD"))},
{V(uint64(1 << 32)), V(string("\uFFFD"))},
{V(uintptr(0x110004)), V(string("\uFFFD"))},
// named string
{V(MyString("hello")), V(string("hello"))},
{V(string("hello")), V(MyString("hello"))},
{V(string("hello")), V(string("hello"))},
{V(MyString("hello")), V(MyString("hello"))},
{V(MyString("bytes1")), V([]byte("bytes1"))},
{V([]byte("bytes2")), V(MyString("bytes2"))},
{V([]byte("bytes3")), V([]byte("bytes3"))},
{V(MyString("runes♝")), V([]rune("runes♝"))},
{V([]rune("runes♕")), V(MyString("runes♕"))},
{V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))},
{V([]rune("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))},
{V(MyRunes("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))},
{V(int('a')), V(MyString("a"))},
{V(int8('a')), V(MyString("a"))},
{V(int16('a')), V(MyString("a"))},
{V(int32('a')), V(MyString("a"))},
{V(int64('a')), V(MyString("a"))},
{V(uint('a')), V(MyString("a"))},
{V(uint8('a')), V(MyString("a"))},
{V(uint16('a')), V(MyString("a"))},
{V(uint32('a')), V(MyString("a"))},
{V(uint64('a')), V(MyString("a"))},
{V(uintptr('a')), V(MyString("a"))},
{V(int(-1)), V(MyString("\uFFFD"))},
{V(int8(-2)), V(MyString("\uFFFD"))},
{V(int16(-3)), V(MyString("\uFFFD"))},
{V(int32(-4)), V(MyString("\uFFFD"))},
{V(int64(-5)), V(MyString("\uFFFD"))},
{V(uint(0x110001)), V(MyString("\uFFFD"))},
{V(uint32(0x110002)), V(MyString("\uFFFD"))},
{V(uint64(0x110003)), V(MyString("\uFFFD"))},
{V(uintptr(0x110004)), V(MyString("\uFFFD"))},
// named []byte
{V(string("bytes1")), V(MyBytes("bytes1"))},
{V(MyBytes("bytes2")), V(string("bytes2"))},
{V(MyBytes("bytes3")), V(MyBytes("bytes3"))},
{V(MyString("bytes1")), V(MyBytes("bytes1"))},
{V(MyBytes("bytes2")), V(MyString("bytes2"))},
// named []rune
{V(string("runes♝")), V(MyRunes("runes♝"))},
{V(MyRunes("runes♕")), V(string("runes♕"))},
{V(MyRunes("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))},
{V(MyString("runes♝")), V(MyRunes("runes♝"))},
{V(MyRunes("runes♕")), V(MyString("runes♕"))},
}
for _, tt := range tests {
+3 -1
View File
@@ -153,7 +153,9 @@ func stringNext(s string, it *stringIterator) (bool, int, rune) {
}
// Convert a Unicode code point into an array of bytes and its length.
func encodeUTF8(x rune) ([4]byte, uintptr) {
func encodeUTF8(r rune) ([4]byte, uintptr) {
x := uint32(r)
// https://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16
// Note: this code can probably be optimized (in size and speed).
switch {