Skip to content

Commit a5b8b56

Browse files
committed
reflect: allow Value.Bytes on addressable byte arrays
Modify Value.Bytes to be callable addressable byte arrays. While related, the behavior of Value.SetBytes was not modified. Fixes #47066 Change-Id: Ic3ba4432353b8da5f33b3188e20034a33b2f6ee8 Reviewed-on: https://go-review.googlesource.com/c/go/+/357331 Trust: Joseph Tsai <[email protected]> Reviewed-by: Keith Randall <[email protected]> Run-TryBot: Joseph Tsai <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent ec4687f commit a5b8b56

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

src/reflect/all_test.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,15 +3682,40 @@ func TestTagGet(t *testing.T) {
36823682
}
36833683

36843684
func TestBytes(t *testing.T) {
3685-
type B []byte
3686-
x := B{1, 2, 3, 4}
3685+
shouldPanic("on int Value", func() { ValueOf(0).Bytes() })
3686+
shouldPanic("of non-byte slice", func() { ValueOf([]string{}).Bytes() })
3687+
3688+
type S []byte
3689+
x := S{1, 2, 3, 4}
36873690
y := ValueOf(x).Bytes()
36883691
if !bytes.Equal(x, y) {
36893692
t.Fatalf("ValueOf(%v).Bytes() = %v", x, y)
36903693
}
36913694
if &x[0] != &y[0] {
36923695
t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
36933696
}
3697+
3698+
type A [4]byte
3699+
a := A{1, 2, 3, 4}
3700+
shouldPanic("unaddressable", func() { ValueOf(a).Bytes() })
3701+
shouldPanic("on ptr Value", func() { ValueOf(&a).Bytes() })
3702+
b := ValueOf(&a).Elem().Bytes()
3703+
if !bytes.Equal(a[:], y) {
3704+
t.Fatalf("ValueOf(%v).Bytes() = %v", a, b)
3705+
}
3706+
if &a[0] != &b[0] {
3707+
t.Errorf("ValueOf(%p).Bytes() = %p", &a[0], &b[0])
3708+
}
3709+
3710+
// Per issue #24746, it was decided that Bytes can be called on byte slices
3711+
// that normally cannot be converted from per Go language semantics.
3712+
type B byte
3713+
type SB []B
3714+
type AB [4]B
3715+
ValueOf([]B{1, 2, 3, 4}).Bytes() // should not panic
3716+
ValueOf(new([4]B)).Elem().Bytes() // should not panic
3717+
ValueOf(SB{1, 2, 3, 4}).Bytes() // should not panic
3718+
ValueOf(new(AB)).Elem().Bytes() // should not panic
36943719
}
36953720

36963721
func TestSetBytes(t *testing.T) {

src/reflect/value.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,28 @@ func (v Value) Bool() bool {
286286
}
287287

288288
// Bytes returns v's underlying value.
289-
// It panics if v's underlying value is not a slice of bytes.
289+
// It panics if v's underlying value is not a slice of bytes or
290+
// an addressable array of bytes.
290291
func (v Value) Bytes() []byte {
291-
v.mustBe(Slice)
292-
if v.typ.Elem().Kind() != Uint8 {
293-
panic("reflect.Value.Bytes of non-byte slice")
292+
switch v.kind() {
293+
case Slice:
294+
if v.typ.Elem().Kind() != Uint8 {
295+
panic("reflect.Value.Bytes of non-byte slice")
296+
}
297+
// Slice is always bigger than a word; assume flagIndir.
298+
return *(*[]byte)(v.ptr)
299+
case Array:
300+
if v.typ.Elem().Kind() != Uint8 {
301+
panic("reflect.Value.Bytes of non-byte array")
302+
}
303+
if !v.CanAddr() {
304+
panic("reflect.Value.Bytes of unaddressable byte array")
305+
}
306+
p := (*byte)(v.ptr)
307+
n := int((*arrayType)(unsafe.Pointer(v.typ)).len)
308+
return unsafe.Slice(p, n)
294309
}
295-
// Slice is always bigger than a word; assume flagIndir.
296-
return *(*[]byte)(v.ptr)
310+
panic(&ValueError{"reflect.Value.Bytes", v.kind()})
297311
}
298312

299313
// runes returns v's underlying value.

0 commit comments

Comments
 (0)