aboutsummaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorCuong Manh Le <cuong.manhle.vn@gmail.com>2023-08-08 12:58:33 +0700
committerGopher Robot <gobot@golang.org>2024-04-02 21:51:18 +0000
commitd08a957298c961a26436d3991028f68ff36cfbfc (patch)
tree38bab08b7ed6a1b009008f862f48f237ad8ec0b6 /src/reflect
parent3d61f24835e477250c98da846206d573a907099c (diff)
downloadgo-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.go41
-rw-r--r--src/reflect/value.go13
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.