]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: allow Value.Bytes on addressable byte arrays
authorJoe Tsai <joetsai@digital-static.net>
Sat, 4 Sep 2021 20:02:09 +0000 (13:02 -0700)
committerJoseph Tsai <joetsai@digital-static.net>
Wed, 2 Mar 2022 18:06:42 +0000 (18:06 +0000)
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 <joetsai@digital-static.net>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/reflect/all_test.go
src/reflect/value.go

index 866f38e68745d318ae60fae3f63f252a4f969650..5364166eab436ccf05510842898144f9ec392c41 100644 (file)
@@ -3682,8 +3682,11 @@ func TestTagGet(t *testing.T) {
 }
 
 func TestBytes(t *testing.T) {
-       type B []byte
-       x := B{1, 2, 3, 4}
+       shouldPanic("on int Value", func() { ValueOf(0).Bytes() })
+       shouldPanic("of non-byte slice", func() { ValueOf([]string{}).Bytes() })
+
+       type S []byte
+       x := S{1, 2, 3, 4}
        y := ValueOf(x).Bytes()
        if !bytes.Equal(x, y) {
                t.Fatalf("ValueOf(%v).Bytes() = %v", x, y)
@@ -3691,6 +3694,28 @@ func TestBytes(t *testing.T) {
        if &x[0] != &y[0] {
                t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
        }
+
+       type A [4]byte
+       a := A{1, 2, 3, 4}
+       shouldPanic("unaddressable", func() { ValueOf(a).Bytes() })
+       shouldPanic("on ptr Value", func() { ValueOf(&a).Bytes() })
+       b := ValueOf(&a).Elem().Bytes()
+       if !bytes.Equal(a[:], y) {
+               t.Fatalf("ValueOf(%v).Bytes() = %v", a, b)
+       }
+       if &a[0] != &b[0] {
+               t.Errorf("ValueOf(%p).Bytes() = %p", &a[0], &b[0])
+       }
+
+       // Per issue #24746, it was decided that Bytes can be called on byte slices
+       // that normally cannot be converted from per Go language semantics.
+       type B byte
+       type SB []B
+       type AB [4]B
+       ValueOf([]B{1, 2, 3, 4}).Bytes()  // should not panic
+       ValueOf(new([4]B)).Elem().Bytes() // should not panic
+       ValueOf(SB{1, 2, 3, 4}).Bytes()   // should not panic
+       ValueOf(new(AB)).Elem().Bytes()   // should not panic
 }
 
 func TestSetBytes(t *testing.T) {
index dcc359dae480b7c0ece698cb169d83027c0eeec2..89f0253570aa94b6c3a90ef835becf08bba4cd54 100644 (file)
@@ -286,14 +286,28 @@ func (v Value) Bool() bool {
 }
 
 // Bytes returns v's underlying value.
-// It panics if v's underlying value is not a slice of bytes.
+// It panics if v's underlying value is not a slice of bytes or
+// an addressable array of bytes.
 func (v Value) Bytes() []byte {
-       v.mustBe(Slice)
-       if v.typ.Elem().Kind() != Uint8 {
-               panic("reflect.Value.Bytes of non-byte slice")
+       switch v.kind() {
+       case Slice:
+               if v.typ.Elem().Kind() != Uint8 {
+                       panic("reflect.Value.Bytes of non-byte slice")
+               }
+               // Slice is always bigger than a word; assume flagIndir.
+               return *(*[]byte)(v.ptr)
+       case Array:
+               if v.typ.Elem().Kind() != Uint8 {
+                       panic("reflect.Value.Bytes of non-byte array")
+               }
+               if !v.CanAddr() {
+                       panic("reflect.Value.Bytes of unaddressable byte array")
+               }
+               p := (*byte)(v.ptr)
+               n := int((*arrayType)(unsafe.Pointer(v.typ)).len)
+               return unsafe.Slice(p, n)
        }
-       // Slice is always bigger than a word; assume flagIndir.
-       return *(*[]byte)(v.ptr)
+       panic(&ValueError{"reflect.Value.Bytes", v.kind()})
 }
 
 // runes returns v's underlying value.