summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/fdchannel/BUILD7
-rw-r--r--pkg/fdchannel/fdchannel_unsafe.go9
-rw-r--r--pkg/flipcall/flipcall_unsafe.go13
-rw-r--r--pkg/gohacks/gohacks_unsafe.go38
-rw-r--r--pkg/safemem/BUILD5
-rw-r--r--pkg/safemem/block_unsafe.go13
-rw-r--r--pkg/safemem/seq_unsafe.go7
-rw-r--r--pkg/sentry/arch/stack_unsafe.go23
-rw-r--r--pkg/sentry/vfs/mount_unsafe.go5
-rw-r--r--pkg/sync/generic_atomicptrmap_unsafe.go7
-rw-r--r--pkg/usermem/addr_range_seq_unsafe.go7
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)