diff options
author | Cuong Manh Le <cuong.manhle.vn@gmail.com> | 2023-08-08 12:58:33 +0700 |
---|---|---|
committer | Gopher Robot <gobot@golang.org> | 2024-04-02 21:51:18 +0000 |
commit | d08a957298c961a26436d3991028f68ff36cfbfc (patch) | |
tree | 38bab08b7ed6a1b009008f862f48f237ad8ec0b6 /src/reflect | |
parent | 3d61f24835e477250c98da846206d573a907099c (diff) | |
download | go-d08a957298c961a26436d3991028f68ff36cfbfc.tar.gz go-d08a957298c961a26436d3991028f68ff36cfbfc.zip |
all: add reflect.SliceAt function
Fixes #61308
Change-Id: Ic17d737fda055a60779985d5da497745c80d5cfa
Reviewed-on: https://go-review.googlesource.com/c/go/+/516597
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/all_test.go | 41 | ||||
-rw-r--r-- | src/reflect/value.go | 13 |
2 files changed, 54 insertions, 0 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index daeabae933..f9b2ffd4f1 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -8548,3 +8548,44 @@ func TestValuePointerAndUnsafePointer(t *testing.T) { }) } } + +// Test cases copied from ../../test/unsafebuiltins.go +func TestSliceAt(t *testing.T) { + const maxUintptr = 1 << (8 * unsafe.Sizeof(uintptr(0))) + var p [10]byte + + typ := TypeOf(p[0]) + + s := SliceAt(typ, unsafe.Pointer(&p[0]), len(p)) + if s.Pointer() != uintptr(unsafe.Pointer(&p[0])) { + t.Fatalf("unexpected underlying array: %d, want: %d", s.Pointer(), uintptr(unsafe.Pointer(&p[0]))) + } + if s.Len() != len(p) || s.Cap() != len(p) { + t.Fatalf("unexpected len or cap, len: %d, cap: %d, want: %d", s.Len(), s.Cap(), len(p)) + } + + typ = TypeOf(0) + if !SliceAt(typ, unsafe.Pointer((*int)(nil)), 0).IsNil() { + t.Fatal("nil pointer with zero length must return nil") + } + + // nil pointer with positive length panics + shouldPanic("", func() { _ = SliceAt(typ, unsafe.Pointer((*int)(nil)), 1) }) + + // negative length + var neg int = -1 + shouldPanic("", func() { _ = SliceAt(TypeOf(byte(0)), unsafe.Pointer(&p[0]), neg) }) + + // size overflows address space + n := uint64(0) + shouldPanic("", func() { _ = SliceAt(TypeOf(n), unsafe.Pointer(&n), maxUintptr/8) }) + shouldPanic("", func() { _ = SliceAt(TypeOf(n), unsafe.Pointer(&n), maxUintptr/8+1) }) + + // sliced memory overflows address space + last := (*byte)(unsafe.Pointer(^uintptr(0))) + // This panics here, but won't panic in ../../test/unsafebuiltins.go, + // because unsafe.Slice(last, 1) does not escape. + // + // _ = SliceAt(typ, unsafe.Pointer(last), 1) + shouldPanic("", func() { _ = SliceAt(typ, unsafe.Pointer(last), 2) }) +} diff --git a/src/reflect/value.go b/src/reflect/value.go index dd7021b104..d14e01ae0c 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -3211,6 +3211,16 @@ func MakeSlice(typ Type, len, cap int) Value { return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)} } +// SliceAt returns a [Value] representing a slice whose underlying +// data starts at p, with length and capacity equal to n. +// +// This is like [unsafe.Slice]. +func SliceAt(typ Type, p unsafe.Pointer, n int) Value { + unsafeslice(typ.common(), p, n) + s := unsafeheader.Slice{Data: p, Len: n, Cap: n} + return Value{SliceOf(typ).common(), unsafe.Pointer(&s), flagIndir | flag(Slice)} +} + // MakeChan creates a new channel with the specified type and buffer size. func MakeChan(typ Type, buffer int) Value { if typ.Kind() != Chan { @@ -3978,6 +3988,9 @@ func verifyNotInHeapPtr(p uintptr) bool //go:noescape func growslice(t *abi.Type, old unsafeheader.Slice, num int) unsafeheader.Slice +//go:noescape +func unsafeslice(t *abi.Type, ptr unsafe.Pointer, len int) + // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. |