diff options
-rw-r--r-- | pkg/fdchannel/BUILD | 7 | ||||
-rw-r--r-- | pkg/fdchannel/fdchannel_unsafe.go | 9 | ||||
-rw-r--r-- | pkg/flipcall/flipcall_unsafe.go | 13 | ||||
-rw-r--r-- | pkg/gohacks/gohacks_unsafe.go | 38 | ||||
-rw-r--r-- | pkg/safemem/BUILD | 5 | ||||
-rw-r--r-- | pkg/safemem/block_unsafe.go | 13 | ||||
-rw-r--r-- | pkg/safemem/seq_unsafe.go | 7 | ||||
-rw-r--r-- | pkg/sentry/arch/stack_unsafe.go | 23 | ||||
-rw-r--r-- | pkg/sentry/vfs/mount_unsafe.go | 5 | ||||
-rw-r--r-- | pkg/sync/generic_atomicptrmap_unsafe.go | 7 | ||||
-rw-r--r-- | pkg/usermem/addr_range_seq_unsafe.go | 7 |
11 files changed, 72 insertions, 62 deletions
diff --git a/pkg/fdchannel/BUILD b/pkg/fdchannel/BUILD index d9104ef02..0b34cef03 100644 --- a/pkg/fdchannel/BUILD +++ b/pkg/fdchannel/BUILD @@ -6,6 +6,9 @@ go_library( name = "fdchannel", srcs = ["fdchannel_unsafe.go"], visibility = ["//visibility:public"], + deps = [ + "//pkg/gohacks", + ], ) go_test( @@ -13,5 +16,7 @@ go_test( size = "small", srcs = ["fdchannel_test.go"], library = ":fdchannel", - deps = ["//pkg/sync"], + deps = [ + "//pkg/sync", + ], ) diff --git a/pkg/fdchannel/fdchannel_unsafe.go b/pkg/fdchannel/fdchannel_unsafe.go index b253a8fdd..0ebdedf26 100644 --- a/pkg/fdchannel/fdchannel_unsafe.go +++ b/pkg/fdchannel/fdchannel_unsafe.go @@ -20,9 +20,10 @@ package fdchannel import ( "fmt" - "reflect" "syscall" "unsafe" + + "gvisor.dev/gvisor/pkg/gohacks" ) // int32 is the real type of a file descriptor. @@ -53,10 +54,10 @@ func (ep *Endpoint) Init(sockfd int) { // sendmsg+recvmsg for a zero-length datagram is slightly faster than // sendmsg+recvmsg for a single byte over a stream socket. cmsgSlice := make([]byte, syscall.CmsgSpace(sizeofInt32)) - cmsgReflect := (*reflect.SliceHeader)(unsafe.Pointer(&cmsgSlice)) + cmsgSliceHdr := (*gohacks.SliceHeader)(unsafe.Pointer(&cmsgSlice)) ep.sockfd = int32(sockfd) - ep.msghdr.Control = (*byte)(unsafe.Pointer(cmsgReflect.Data)) - ep.cmsg = (*syscall.Cmsghdr)(unsafe.Pointer(cmsgReflect.Data)) + ep.msghdr.Control = (*byte)(cmsgSliceHdr.Data) + ep.cmsg = (*syscall.Cmsghdr)(cmsgSliceHdr.Data) // ep.msghdr.Controllen and ep.cmsg.* are mutated by recvmsg(2), so they're // set before calling sendmsg/recvmsg. } diff --git a/pkg/flipcall/flipcall_unsafe.go b/pkg/flipcall/flipcall_unsafe.go index 580bf23a4..613ed8943 100644 --- a/pkg/flipcall/flipcall_unsafe.go +++ b/pkg/flipcall/flipcall_unsafe.go @@ -61,13 +61,12 @@ func (ep *Endpoint) dataLen() *uint32 { // - Writers must not assume that they will read back the same data that they // have written. In other words, writers should avoid reading from Data() at // all. -func (ep *Endpoint) Data() []byte { - var bs []byte - bsReflect := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) - bsReflect.Data = ep.packet + PacketHeaderBytes - bsReflect.Len = int(ep.dataCap) - bsReflect.Cap = int(ep.dataCap) - return bs +func (ep *Endpoint) Data() (bs []byte) { + bshdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) + bshdr.Data = ep.packet + PacketHeaderBytes + bshdr.Len = int(ep.dataCap) + bshdr.Cap = int(ep.dataCap) + return } // ioSync is a dummy variable used to indicate synchronization to the Go race diff --git a/pkg/gohacks/gohacks_unsafe.go b/pkg/gohacks/gohacks_unsafe.go index aad675172..d26c1ac05 100644 --- a/pkg/gohacks/gohacks_unsafe.go +++ b/pkg/gohacks/gohacks_unsafe.go @@ -12,14 +12,35 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build go1.13 +// +build !go1.17 + +// Check type signatures when updating Go version. + // Package gohacks contains utilities for subverting the Go compiler. package gohacks import ( - "reflect" "unsafe" ) +// SliceHeader is equivalent to reflect.SliceHeader, but represents the pointer +// to the underlying array as unsafe.Pointer rather than uintptr, allowing +// SliceHeaders to be directly converted to slice objects. +type SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +// StringHeader is equivalent to reflect.StringHeader, but represents the +// pointer to the underlying array as unsafe.Pointer rather than uintptr, +// allowing StringHeaders to be directly converted to strings. +type StringHeader struct { + Data unsafe.Pointer + Len int +} + // Noescape hides a pointer from escape analysis. Noescape is the identity // function but escape analysis doesn't think the output depends on the input. // Noescape is inlined and currently compiles down to zero instructions. @@ -36,22 +57,21 @@ func Noescape(p unsafe.Pointer) unsafe.Pointer { // ImmutableBytesFromString is equivalent to []byte(s), except that it uses the // same memory backing s instead of making a heap-allocated copy. This is only // valid if the returned slice is never mutated. -func ImmutableBytesFromString(s string) []byte { - shdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - var bs []byte - bshdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) +func ImmutableBytesFromString(s string) (bs []byte) { + shdr := (*StringHeader)(unsafe.Pointer(&s)) + bshdr := (*SliceHeader)(unsafe.Pointer(&bs)) bshdr.Data = shdr.Data bshdr.Len = shdr.Len bshdr.Cap = shdr.Len - return bs + return } // StringFromImmutableBytes is equivalent to string(bs), except that it uses // the same memory backing bs instead of making a heap-allocated copy. This is // only valid if bs is never mutated after StringFromImmutableBytes returns. func StringFromImmutableBytes(bs []byte) string { - // This is cheaper than messing with reflect.StringHeader and - // reflect.SliceHeader, which as of this writing produces many dead stores - // of zeroes. Compare strings.Builder.String(). + // This is cheaper than messing with StringHeader and SliceHeader, which as + // of this writing produces many dead stores of zeroes. Compare + // strings.Builder.String(). return *(*string)(unsafe.Pointer(&bs)) } diff --git a/pkg/safemem/BUILD b/pkg/safemem/BUILD index 68ed074f8..d3b9b0ca9 100644 --- a/pkg/safemem/BUILD +++ b/pkg/safemem/BUILD @@ -11,7 +11,10 @@ go_library( "seq_unsafe.go", ], visibility = ["//:sandbox"], - deps = ["//pkg/safecopy"], + deps = [ + "//pkg/gohacks", + "//pkg/safecopy", + ], ) go_test( diff --git a/pkg/safemem/block_unsafe.go b/pkg/safemem/block_unsafe.go index 7857f5853..93879bb4f 100644 --- a/pkg/safemem/block_unsafe.go +++ b/pkg/safemem/block_unsafe.go @@ -16,9 +16,9 @@ package safemem import ( "fmt" - "reflect" "unsafe" + "gvisor.dev/gvisor/pkg/gohacks" "gvisor.dev/gvisor/pkg/safecopy" ) @@ -148,12 +148,11 @@ func (b Block) TakeFirst64(n uint64) Block { // ToSlice returns a []byte equivalent to b. func (b Block) ToSlice() []byte { - var bs []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) - hdr.Data = uintptr(b.start) - hdr.Len = b.length - hdr.Cap = b.length - return bs + return *(*[]byte)(unsafe.Pointer(&gohacks.SliceHeader{ + Data: b.start, + Len: b.length, + Cap: b.length, + })) } // Addr returns b's start address as a uintptr. It returns uintptr instead of diff --git a/pkg/safemem/seq_unsafe.go b/pkg/safemem/seq_unsafe.go index fc4049eeb..b315b0e5a 100644 --- a/pkg/safemem/seq_unsafe.go +++ b/pkg/safemem/seq_unsafe.go @@ -17,9 +17,10 @@ package safemem import ( "bytes" "fmt" - "reflect" "syscall" "unsafe" + + "gvisor.dev/gvisor/pkg/gohacks" ) // A BlockSeq represents a sequence of Blocks, each of which has non-zero @@ -184,8 +185,8 @@ func (bs BlockSeq) Tail() BlockSeq { return BlockSeq{} } var extSlice []Block - extSliceHdr := (*reflect.SliceHeader)(unsafe.Pointer(&extSlice)) - extSliceHdr.Data = uintptr(bs.data) + extSliceHdr := (*gohacks.SliceHeader)(unsafe.Pointer(&extSlice)) + extSliceHdr.Data = bs.data extSliceHdr.Len = bs.length extSliceHdr.Cap = bs.length tailSlice := skipEmpty(extSlice[1:]) diff --git a/pkg/sentry/arch/stack_unsafe.go b/pkg/sentry/arch/stack_unsafe.go index a90d297ee..0e478e434 100644 --- a/pkg/sentry/arch/stack_unsafe.go +++ b/pkg/sentry/arch/stack_unsafe.go @@ -15,8 +15,6 @@ package arch import ( - "reflect" - "runtime" "unsafe" "gvisor.dev/gvisor/pkg/marshal/primitive" @@ -33,35 +31,22 @@ import ( // On error, the contents of the stack and the bottom cursor are undefined. func (s *Stack) pushAddrSliceAndTerminator(src []usermem.Addr) (int, error) { // Note: Stack grows upwards, so push the terminator first. - srcHdr := (*reflect.SliceHeader)(unsafe.Pointer(&src)) switch s.Arch.Width() { case 8: nNull, err := primitive.CopyUint64Out(s, StackBottomMagic, 0) if err != nil { return 0, err } - var dst []uint64 - dstHdr := (*reflect.SliceHeader)(unsafe.Pointer(&dst)) - dstHdr.Data = srcHdr.Data - dstHdr.Len = srcHdr.Len - dstHdr.Cap = srcHdr.Cap - n, err := primitive.CopyUint64SliceOut(s, StackBottomMagic, dst) - // Ensures src doesn't get GCed until we're done using it through dst. - runtime.KeepAlive(src) + srcAsUint64 := *(*[]uint64)(unsafe.Pointer(&src)) + n, err := primitive.CopyUint64SliceOut(s, StackBottomMagic, srcAsUint64) return n + nNull, err case 4: nNull, err := primitive.CopyUint32Out(s, StackBottomMagic, 0) if err != nil { return 0, err } - var dst []uint32 - dstHdr := (*reflect.SliceHeader)(unsafe.Pointer(&dst)) - dstHdr.Data = srcHdr.Data - dstHdr.Len = srcHdr.Len - dstHdr.Cap = srcHdr.Cap - n, err := primitive.CopyUint32SliceOut(s, StackBottomMagic, dst) - // Ensure src doesn't get GCed until we're done using it through dst. - runtime.KeepAlive(src) + srcAsUint32 := *(*[]uint32)(unsafe.Pointer(&src)) + n, err := primitive.CopyUint32SliceOut(s, StackBottomMagic, srcAsUint32) return n + nNull, err default: panic("Unsupported arch width") diff --git a/pkg/sentry/vfs/mount_unsafe.go b/pkg/sentry/vfs/mount_unsafe.go index 0df023713..c7a78d8f8 100644 --- a/pkg/sentry/vfs/mount_unsafe.go +++ b/pkg/sentry/vfs/mount_unsafe.go @@ -17,7 +17,6 @@ package vfs import ( "fmt" "math/bits" - "reflect" "sync/atomic" "unsafe" @@ -153,8 +152,8 @@ func (mt *mountTable) Init() { func newMountTableSlots(cap uintptr) unsafe.Pointer { slice := make([]mountSlot, cap, cap) - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice)) - return unsafe.Pointer(hdr.Data) + hdr := (*gohacks.SliceHeader)(unsafe.Pointer(&slice)) + return hdr.Data } // Lookup returns the Mount with the given parent, mounted at the given point. diff --git a/pkg/sync/generic_atomicptrmap_unsafe.go b/pkg/sync/generic_atomicptrmap_unsafe.go index c70dda6dd..3e98cb309 100644 --- a/pkg/sync/generic_atomicptrmap_unsafe.go +++ b/pkg/sync/generic_atomicptrmap_unsafe.go @@ -17,8 +17,6 @@ package atomicptrmap import ( - "reflect" - "runtime" "sync/atomic" "unsafe" @@ -372,9 +370,8 @@ func (shard *apmShard) rehash(oldSlots unsafe.Pointer) { // Allocate the new table. newSlotsSlice := make([]apmSlot, newSize) - newSlotsReflect := (*reflect.SliceHeader)(unsafe.Pointer(&newSlotsSlice)) - newSlots := unsafe.Pointer(newSlotsReflect.Data) - runtime.KeepAlive(newSlotsSlice) + newSlotsHeader := (*gohacks.SliceHeader)(unsafe.Pointer(&newSlotsSlice)) + newSlots := newSlotsHeader.Data newMask := newSize - 1 // Start a writer critical section now so that racing users of the old diff --git a/pkg/usermem/addr_range_seq_unsafe.go b/pkg/usermem/addr_range_seq_unsafe.go index 495896ded..c9a1415a0 100644 --- a/pkg/usermem/addr_range_seq_unsafe.go +++ b/pkg/usermem/addr_range_seq_unsafe.go @@ -17,8 +17,9 @@ package usermem import ( "bytes" "fmt" - "reflect" "unsafe" + + "gvisor.dev/gvisor/pkg/gohacks" ) // An AddrRangeSeq represents a sequence of AddrRanges. @@ -163,8 +164,8 @@ func (ars AddrRangeSeq) externalTail() AddrRangeSeq { tailLimit = int64(ars.limit - headLen) } var extSlice []AddrRange - extSliceHdr := (*reflect.SliceHeader)(unsafe.Pointer(&extSlice)) - extSliceHdr.Data = uintptr(ars.data) + extSliceHdr := (*gohacks.SliceHeader)(unsafe.Pointer(&extSlice)) + extSliceHdr.Data = ars.data extSliceHdr.Len = ars.length extSliceHdr.Cap = ars.length return addrRangeSeqFromSliceLimited(extSlice[1:], tailLimit) |