From c7085329367e14f0aa828a3793cf66d9f82f05c2 Mon Sep 17 00:00:00 2001 From: cuiweixie Date: Tue, 16 Aug 2022 17:52:13 +0800 Subject: cmd/compile: add support for unsafe.{String,StringData,SliceData} For #53003 Change-Id: I13a761daca8b433b271a1feb711c103d9820772d Reviewed-on: https://go-review.googlesource.com/c/go/+/423774 Reviewed-by: Heschi Kreinick Reviewed-by: Matthew Dempsky Reviewed-by: hopehook Reviewed-by: Cuong Manh Le Reviewed-by: Keith Randall Run-TryBot: Matthew Dempsky TryBot-Result: Gopher Robot --- src/runtime/checkptr_test.go | 2 + src/runtime/slice.go | 48 --------------- src/runtime/testdata/testprog/checkptr.go | 13 ++++ src/runtime/unsafe.go | 98 +++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 48 deletions(-) create mode 100644 src/runtime/unsafe.go (limited to 'src/runtime') diff --git a/src/runtime/checkptr_test.go b/src/runtime/checkptr_test.go index 15011ec494..811c0f0355 100644 --- a/src/runtime/checkptr_test.go +++ b/src/runtime/checkptr_test.go @@ -39,6 +39,8 @@ func TestCheckPtr(t *testing.T) { {"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"}, {"CheckPtrSliceOK", ""}, {"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"}, + {"CheckPtrStringOK", ""}, + {"CheckPtrStringFail", "fatal error: checkptr: unsafe.String result straddles multiple allocations\n"}, } for _, tc := range testCases { diff --git a/src/runtime/slice.go b/src/runtime/slice.go index e537f15826..0a203e4101 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -123,54 +123,6 @@ func mulUintptr(a, b uintptr) (uintptr, bool) { return math.MulUintptr(a, b) } -// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice -func unsafeslice(et *_type, ptr unsafe.Pointer, len int) { - if len < 0 { - panicunsafeslicelen() - } - - if et.size == 0 { - if ptr == nil && len > 0 { - panicunsafeslicenilptr() - } - } - - mem, overflow := math.MulUintptr(et.size, uintptr(len)) - if overflow || mem > -uintptr(ptr) { - if ptr == nil { - panicunsafeslicenilptr() - } - panicunsafeslicelen() - } -} - -// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice -func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) { - len := int(len64) - if int64(len) != len64 { - panicunsafeslicelen() - } - 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() { - panic(errorString("unsafe.Slice: len out of range")) -} - -func panicunsafeslicenilptr() { - panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) -} - // growslice handles slice growth during append. // It is passed the slice element type, the old slice, and the desired new minimum capacity, // and it returns a new slice with at least that capacity, with the old data diff --git a/src/runtime/testdata/testprog/checkptr.go b/src/runtime/testdata/testprog/checkptr.go index b27e5f74f8..60e71e66d7 100644 --- a/src/runtime/testdata/testprog/checkptr.go +++ b/src/runtime/testdata/testprog/checkptr.go @@ -20,6 +20,8 @@ func init() { register("CheckPtrSmall", CheckPtrSmall) register("CheckPtrSliceOK", CheckPtrSliceOK) register("CheckPtrSliceFail", CheckPtrSliceFail) + register("CheckPtrStringOK", CheckPtrStringOK) + register("CheckPtrStringFail", CheckPtrStringFail) register("CheckPtrAlignmentNested", CheckPtrAlignmentNested) } @@ -98,6 +100,17 @@ func CheckPtrSliceFail() { sink2 = unsafe.Slice(p, 100) } +func CheckPtrStringOK() { + p := new([4]byte) + sink2 = unsafe.String(&p[1], 3) +} + +func CheckPtrStringFail() { + p := new(byte) + sink2 = p + sink2 = unsafe.String(p, 100) +} + func CheckPtrAlignmentNested() { s := make([]int8, 100) p := unsafe.Pointer(&s[0]) diff --git a/src/runtime/unsafe.go b/src/runtime/unsafe.go new file mode 100644 index 0000000000..54649e8ff5 --- /dev/null +++ b/src/runtime/unsafe.go @@ -0,0 +1,98 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "runtime/internal/math" + "unsafe" +) + +func unsafestring(ptr unsafe.Pointer, len int) { + if len < 0 { + panicunsafestringlen() + } + + if uintptr(len) > -uintptr(ptr) { + if ptr == nil { + panicunsafestringnilptr() + } + panicunsafestringlen() + } +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString +func unsafestring64(ptr unsafe.Pointer, len64 int64) { + len := int(len64) + if int64(len) != len64 { + panicunsafestringlen() + } + unsafestring(ptr, len) +} + +func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) { + unsafestring64(ptr, len64) + + // Check that underlying array doesn't straddle multiple heap objects. + // unsafestring64 has already checked for overflow. + if checkptrStraddles(ptr, uintptr(len64)) { + throw("checkptr: unsafe.String result straddles multiple allocations") + } +} + +func panicunsafestringlen() { + panic(errorString("unsafe.String: len out of range")) +} + +func panicunsafestringnilptr() { + panic(errorString("unsafe.String: ptr is nil and len is not zero")) +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice +func unsafeslice(et *_type, ptr unsafe.Pointer, len int) { + if len < 0 { + panicunsafeslicelen() + } + + if et.size == 0 { + if ptr == nil && len > 0 { + panicunsafeslicenilptr() + } + } + + mem, overflow := math.MulUintptr(et.size, uintptr(len)) + if overflow || mem > -uintptr(ptr) { + if ptr == nil { + panicunsafeslicenilptr() + } + panicunsafeslicelen() + } +} + +// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice +func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) { + len := int(len64) + if int64(len) != len64 { + panicunsafeslicelen() + } + 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() { + panic(errorString("unsafe.Slice: len out of range")) +} + +func panicunsafeslicenilptr() { + panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) +} -- cgit v1.3-5-g9baa