| // 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 ( | |
| "internal/runtime/math" | |
| "internal/runtime/sys" | |
| "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 { | |
| panicunsafeslicelen1(sys.GetCallerPC()) | |
| } | |
| if et.Size_ == 0 { | |
| if ptr == nil && len > 0 { | |
| panicunsafeslicenilptr1(sys.GetCallerPC()) | |
| } | |
| } | |
| mem, overflow := math.MulUintptr(et.Size_, uintptr(len)) | |
| if overflow || mem > -uintptr(ptr) { | |
| if ptr == nil { | |
| panicunsafeslicenilptr1(sys.GetCallerPC()) | |
| } | |
| panicunsafeslicelen1(sys.GetCallerPC()) | |
| } | |
| } | |
| // 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 { | |
| panicunsafeslicelen1(sys.GetCallerPC()) | |
| } | |
| 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() { | |
| // This is called only from compiler-generated code, so we can get the | |
| // source of the panic. | |
| panicunsafeslicelen1(sys.GetCallerPC()) | |
| } | |
| //go:yeswritebarrierrec | |
| func panicunsafeslicelen1(pc uintptr) { | |
| panicCheck1(pc, "unsafe.Slice: len out of range") | |
| panic(errorString("unsafe.Slice: len out of range")) | |
| } | |
| func panicunsafeslicenilptr() { | |
| // This is called only from compiler-generated code, so we can get the | |
| // source of the panic. | |
| panicunsafeslicenilptr1(sys.GetCallerPC()) | |
| } | |
| //go:yeswritebarrierrec | |
| 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) | |
| } |