aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/checkptr.go21
-rw-r--r--src/runtime/checkptr_test.go2
-rw-r--r--src/runtime/slice.go24
-rw-r--r--src/runtime/testdata/testprog/checkptr.go13
4 files changed, 56 insertions, 4 deletions
diff --git a/src/runtime/checkptr.go b/src/runtime/checkptr.go
index 59891a06a5..d42950844b 100644
--- a/src/runtime/checkptr.go
+++ b/src/runtime/checkptr.go
@@ -16,11 +16,30 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
}
// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
- if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
+ // TODO(mdempsky): Fix #46938 so we don't need to worry about overflow here.
+ if checkptrStraddles(p, n*elem.size) {
throw("checkptr: converted pointer straddles multiple allocations")
}
}
+// checkptrStraddles reports whether the first size-bytes of memory
+// addressed by ptr is known to straddle more than one Go allocation.
+func checkptrStraddles(ptr unsafe.Pointer, size uintptr) bool {
+ if size <= 1 {
+ return false
+ }
+
+ end := add(ptr, size-1)
+ if uintptr(end) < uintptr(ptr) {
+ return true
+ }
+
+ // TODO(mdempsky): Detect when [ptr, end] contains Go allocations,
+ // but neither ptr nor end point into one themselves.
+
+ return checkptrBase(ptr) != checkptrBase(end)
+}
+
func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
throw("checkptr: pointer arithmetic computed bad pointer value")
diff --git a/src/runtime/checkptr_test.go b/src/runtime/checkptr_test.go
index 194cc1243a..2a5c364e97 100644
--- a/src/runtime/checkptr_test.go
+++ b/src/runtime/checkptr_test.go
@@ -30,6 +30,8 @@ func TestCheckPtr(t *testing.T) {
{"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
+ {"CheckPtrSliceOK", ""},
+ {"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"},
}
for _, tc := range testCases {
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index f9d4154acf..01cdcaeee3 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -112,19 +112,37 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
return makeslice(et, len, cap)
}
-func unsafeslice(et *_type, len int) {
+func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
+ if len == 0 {
+ return
+ }
+
+ if ptr == nil {
+ panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+ }
+
mem, overflow := math.MulUintptr(et.size, uintptr(len))
if overflow || mem > maxAlloc || len < 0 {
panicunsafeslicelen()
}
}
-func unsafeslice64(et *_type, len64 int64) {
+func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
len := int(len64)
if int64(len) != len64 {
panicunsafeslicelen()
}
- unsafeslice(et, len)
+ unsafeslice(et, ptr, len)
+}
+
+func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
+ unsafeslice64(et, ptr, len64)
+
+ // Check that underlying array doesn't straddle multiple heap objects.
+ // unsafeslice64 has already checked for overflow.
+ if checkptrStraddles(ptr, uintptr(len64)*et.size) {
+ throw("checkptr: unsafe.Slice result straddles multiple allocations")
+ }
}
func panicunsafeslicelen() {
diff --git a/src/runtime/testdata/testprog/checkptr.go b/src/runtime/testdata/testprog/checkptr.go
index e0a2794f4c..f76b64ad96 100644
--- a/src/runtime/testdata/testprog/checkptr.go
+++ b/src/runtime/testdata/testprog/checkptr.go
@@ -13,6 +13,8 @@ func init() {
register("CheckPtrArithmetic2", CheckPtrArithmetic2)
register("CheckPtrSize", CheckPtrSize)
register("CheckPtrSmall", CheckPtrSmall)
+ register("CheckPtrSliceOK", CheckPtrSliceOK)
+ register("CheckPtrSliceFail", CheckPtrSliceFail)
}
func CheckPtrAlignmentNoPtr() {
@@ -49,3 +51,14 @@ func CheckPtrSize() {
func CheckPtrSmall() {
sink2 = unsafe.Pointer(uintptr(1))
}
+
+func CheckPtrSliceOK() {
+ p := new([4]int64)
+ sink2 = unsafe.Slice(&p[1], 3)
+}
+
+func CheckPtrSliceFail() {
+ p := new(int64)
+ sink2 = p
+ sink2 = unsafe.Slice(p, 100)
+}