]> Cypherpunks repositories - gostls13.git/commitdiff
all: add reflect.SliceAt function
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Tue, 8 Aug 2023 05:58:33 +0000 (12:58 +0700)
committerGopher Robot <gobot@golang.org>
Tue, 2 Apr 2024 21:51:18 +0000 (21:51 +0000)
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>
api/next/61308.txt [new file with mode: 0644]
doc/next/6-stdlib/99-minor/reflect/61308.md [new file with mode: 0644]
src/reflect/all_test.go
src/reflect/value.go
src/runtime/unsafe.go

diff --git a/api/next/61308.txt b/api/next/61308.txt
new file mode 100644 (file)
index 0000000..73a6035
--- /dev/null
@@ -0,0 +1 @@
+pkg reflect, func SliceAt(Type, unsafe.Pointer, int) Value #61308
diff --git a/doc/next/6-stdlib/99-minor/reflect/61308.md b/doc/next/6-stdlib/99-minor/reflect/61308.md
new file mode 100644 (file)
index 0000000..e512e8f
--- /dev/null
@@ -0,0 +1,3 @@
+The [`SliceAt(typ Type, p unsafe.Pointer, len int)`](/pkg/reflect#SliceAt) function
+returns a Value representing a slice whose underlying array starts at p and whose
+length and capacity are len.
index daeabae933eb9a585bcfbf99a06f7bbbedd49b26..f9b2ffd4f1de268c953cb5edcfe83e28d63a2e64 100644 (file)
@@ -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) })
+}
index dd7021b104f241b5ec1264079152c5c0b72ffe0f..d14e01ae0ce983da95955514a8ca52f13e7567fb 100644 (file)
@@ -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.
index 6675264f5977a8f9b58b54d9df8fb5307728ef8b..ca428b56e079223d6e01695929af704d13de4210 100644 (file)
@@ -112,3 +112,8 @@ func panicunsafeslicenilptr1(pc uintptr) {
        panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero")
        panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
 }
+
+//go:linkname reflect_unsafeslice reflect.unsafeslice
+func reflect_unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
+       unsafeslice(et, ptr, len)
+}