Skip to content

Commit d08a957

Browse files
cuonglmgopherbot
authored andcommitted
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 <[email protected]> Auto-Submit: Cuong Manh Le <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 3d61f24 commit d08a957

File tree

5 files changed

+63
-0
lines changed

5 files changed

+63
-0
lines changed

api/next/61308.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pkg reflect, func SliceAt(Type, unsafe.Pointer, int) Value #61308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The [`SliceAt(typ Type, p unsafe.Pointer, len int)`](/pkg/reflect#SliceAt) function
2+
returns a Value representing a slice whose underlying array starts at p and whose
3+
length and capacity are len.

src/reflect/all_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -8548,3 +8548,44 @@ func TestValuePointerAndUnsafePointer(t *testing.T) {
85488548
})
85498549
}
85508550
}
8551+
8552+
// Test cases copied from ../../test/unsafebuiltins.go
8553+
func TestSliceAt(t *testing.T) {
8554+
const maxUintptr = 1 << (8 * unsafe.Sizeof(uintptr(0)))
8555+
var p [10]byte
8556+
8557+
typ := TypeOf(p[0])
8558+
8559+
s := SliceAt(typ, unsafe.Pointer(&p[0]), len(p))
8560+
if s.Pointer() != uintptr(unsafe.Pointer(&p[0])) {
8561+
t.Fatalf("unexpected underlying array: %d, want: %d", s.Pointer(), uintptr(unsafe.Pointer(&p[0])))
8562+
}
8563+
if s.Len() != len(p) || s.Cap() != len(p) {
8564+
t.Fatalf("unexpected len or cap, len: %d, cap: %d, want: %d", s.Len(), s.Cap(), len(p))
8565+
}
8566+
8567+
typ = TypeOf(0)
8568+
if !SliceAt(typ, unsafe.Pointer((*int)(nil)), 0).IsNil() {
8569+
t.Fatal("nil pointer with zero length must return nil")
8570+
}
8571+
8572+
// nil pointer with positive length panics
8573+
shouldPanic("", func() { _ = SliceAt(typ, unsafe.Pointer((*int)(nil)), 1) })
8574+
8575+
// negative length
8576+
var neg int = -1
8577+
shouldPanic("", func() { _ = SliceAt(TypeOf(byte(0)), unsafe.Pointer(&p[0]), neg) })
8578+
8579+
// size overflows address space
8580+
n := uint64(0)
8581+
shouldPanic("", func() { _ = SliceAt(TypeOf(n), unsafe.Pointer(&n), maxUintptr/8) })
8582+
shouldPanic("", func() { _ = SliceAt(TypeOf(n), unsafe.Pointer(&n), maxUintptr/8+1) })
8583+
8584+
// sliced memory overflows address space
8585+
last := (*byte)(unsafe.Pointer(^uintptr(0)))
8586+
// This panics here, but won't panic in ../../test/unsafebuiltins.go,
8587+
// because unsafe.Slice(last, 1) does not escape.
8588+
//
8589+
// _ = SliceAt(typ, unsafe.Pointer(last), 1)
8590+
shouldPanic("", func() { _ = SliceAt(typ, unsafe.Pointer(last), 2) })
8591+
}

src/reflect/value.go

+13
Original file line numberDiff line numberDiff line change
@@ -3211,6 +3211,16 @@ func MakeSlice(typ Type, len, cap int) Value {
32113211
return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)}
32123212
}
32133213

3214+
// SliceAt returns a [Value] representing a slice whose underlying
3215+
// data starts at p, with length and capacity equal to n.
3216+
//
3217+
// This is like [unsafe.Slice].
3218+
func SliceAt(typ Type, p unsafe.Pointer, n int) Value {
3219+
unsafeslice(typ.common(), p, n)
3220+
s := unsafeheader.Slice{Data: p, Len: n, Cap: n}
3221+
return Value{SliceOf(typ).common(), unsafe.Pointer(&s), flagIndir | flag(Slice)}
3222+
}
3223+
32143224
// MakeChan creates a new channel with the specified type and buffer size.
32153225
func MakeChan(typ Type, buffer int) Value {
32163226
if typ.Kind() != Chan {
@@ -3978,6 +3988,9 @@ func verifyNotInHeapPtr(p uintptr) bool
39783988
//go:noescape
39793989
func growslice(t *abi.Type, old unsafeheader.Slice, num int) unsafeheader.Slice
39803990

3991+
//go:noescape
3992+
func unsafeslice(t *abi.Type, ptr unsafe.Pointer, len int)
3993+
39813994
// Dummy annotation marking that the value x escapes,
39823995
// for use in cases where the reflect code is so clever that
39833996
// the compiler cannot follow.

src/runtime/unsafe.go

+5
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,8 @@ func panicunsafeslicenilptr1(pc uintptr) {
112112
panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero")
113113
panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
114114
}
115+
116+
//go:linkname reflect_unsafeslice reflect.unsafeslice
117+
func reflect_unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
118+
unsafeslice(et, ptr, len)
119+
}

0 commit comments

Comments
 (0)