diff options
author | Keith Randall <khr@golang.org> | 2021-05-09 11:06:17 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2021-05-10 13:16:56 +0000 |
commit | 287025925f66f90ad9b30aea2e533928026a8376 (patch) | |
tree | d1d08af3e2dbb39ee461a3d9bc821b406e6a384b /src/internal | |
parent | c14ecaca8182314efd2ef7280feffc2242644887 (diff) | |
download | go-287025925f66f90ad9b30aea2e533928026a8376.tar.gz go-287025925f66f90ad9b30aea2e533928026a8376.zip |
cmd/compile,reflect: allow longer type names
Encode the length of type names and tags in a varint encoding
instead of a fixed 2-byte encoding. This allows lengths longer
than 65535 (which can happen for large unnamed structs).
Removed the alignment check for #14962, it isn't relevant any more
since we're no longer reading pointers directly out of this data
(it is encoded as an offset which is copied out bytewise).
Fixes #44155
Update #14962
Change-Id: I6084f6027e5955dc16777c87b0dd5ea2baa49629
Reviewed-on: https://go-review.googlesource.com/c/go/+/318249
Trust: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/internal')
-rw-r--r-- | src/internal/reflectlite/all_test.go | 13 | ||||
-rw-r--r-- | src/internal/reflectlite/type.go | 52 |
2 files changed, 29 insertions, 36 deletions
diff --git a/src/internal/reflectlite/all_test.go b/src/internal/reflectlite/all_test.go index e2c4f30487..e15f364fcd 100644 --- a/src/internal/reflectlite/all_test.go +++ b/src/internal/reflectlite/all_test.go @@ -982,19 +982,6 @@ func TestNames(t *testing.T) { } } -type embed struct { - EmbedWithUnexpMeth -} - -func TestNameBytesAreAligned(t *testing.T) { - typ := TypeOf(embed{}) - b := FirstMethodNameBytes(typ) - v := uintptr(unsafe.Pointer(b)) - if v%unsafe.Alignof((*byte)(nil)) != 0 { - t.Errorf("reflect.name.bytes pointer is not aligned: %x", v) - } -} - // TestUnaddressableField tests that the reflect package will not allow // a type from another package to be used as a named type with an // unexported field. diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index 15ba30da36..f529f7c5fc 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -321,49 +321,55 @@ func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n name) nameLen() int { - return int(uint16(*n.data(1, "name len field"))<<8 | uint16(*n.data(2, "name len field"))) -} - -func (n name) tagLen() int { - if *n.data(0, "name flag field")&(1<<1) == 0 { - return 0 +func (n name) hasTag() bool { + return (*n.bytes)&(1<<1) != 0 +} + +// readVarint parses a varint as encoded by encoding/binary. +// It returns the number of encoded bytes and the encoded value. +func (n name) readVarint(off int) (int, int) { + v := 0 + for i := 0; ; i++ { + x := *n.data(off+i, "read varint") + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v + } } - off := 3 + n.nameLen() - return int(uint16(*n.data(off, "name taglen field"))<<8 | uint16(*n.data(off+1, "name taglen field"))) } func (n name) name() (s string) { if n.bytes == nil { return } - b := (*[4]byte)(unsafe.Pointer(n.bytes)) - + i, l := n.readVarint(1) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(&b[3]) - hdr.Len = int(b[1])<<8 | int(b[2]) - return s + hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string")) + hdr.Len = l + return } func (n name) tag() (s string) { - tl := n.tagLen() - if tl == 0 { + if !n.hasTag() { return "" } - nl := n.nameLen() + i, l := n.readVarint(1) + i2, l2 := n.readVarint(1 + i + l) hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string")) - hdr.Len = tl - return s + hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string")) + hdr.Len = l2 + return } func (n name) pkgPath() string { if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 { return "" } - off := 3 + n.nameLen() - if tl := n.tagLen(); tl > 0 { - off += 2 + tl + i, l := n.readVarint(1) + off := 1 + i + l + if n.hasTag() { + i2, l2 := n.readVarint(off) + off += i2 + l2 } var nameOff int32 // Note that this field may not be aligned in memory, |