Source file src/runtime/unsafe.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import (
     8  	"internal/runtime/math"
     9  	"internal/runtime/sys"
    10  	"unsafe"
    11  )
    12  
    13  func unsafestring(ptr unsafe.Pointer, len int) {
    14  	if len < 0 {
    15  		panicunsafestringlen()
    16  	}
    17  
    18  	if uintptr(len) > -uintptr(ptr) {
    19  		if ptr == nil {
    20  			panicunsafestringnilptr()
    21  		}
    22  		panicunsafestringlen()
    23  	}
    24  }
    25  
    26  // Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString
    27  func unsafestring64(ptr unsafe.Pointer, len64 int64) {
    28  	len := int(len64)
    29  	if int64(len) != len64 {
    30  		panicunsafestringlen()
    31  	}
    32  	unsafestring(ptr, len)
    33  }
    34  
    35  func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) {
    36  	unsafestring64(ptr, len64)
    37  
    38  	// Check that underlying array doesn't straddle multiple heap objects.
    39  	// unsafestring64 has already checked for overflow.
    40  	if checkptrStraddles(ptr, uintptr(len64)) {
    41  		throw("checkptr: unsafe.String result straddles multiple allocations")
    42  	}
    43  }
    44  
    45  func panicunsafestringlen() {
    46  	panic(errorString("unsafe.String: len out of range"))
    47  }
    48  
    49  func panicunsafestringnilptr() {
    50  	panic(errorString("unsafe.String: ptr is nil and len is not zero"))
    51  }
    52  
    53  // Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
    54  func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
    55  	if len < 0 {
    56  		panicunsafeslicelen1(sys.GetCallerPC())
    57  	}
    58  
    59  	if et.Size_ == 0 {
    60  		if ptr == nil && len > 0 {
    61  			panicunsafeslicenilptr1(sys.GetCallerPC())
    62  		}
    63  	}
    64  
    65  	mem, overflow := math.MulUintptr(et.Size_, uintptr(len))
    66  	if overflow || mem > -uintptr(ptr) {
    67  		if ptr == nil {
    68  			panicunsafeslicenilptr1(sys.GetCallerPC())
    69  		}
    70  		panicunsafeslicelen1(sys.GetCallerPC())
    71  	}
    72  }
    73  
    74  // Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
    75  func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
    76  	len := int(len64)
    77  	if int64(len) != len64 {
    78  		panicunsafeslicelen1(sys.GetCallerPC())
    79  	}
    80  	unsafeslice(et, ptr, len)
    81  }
    82  
    83  func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
    84  	unsafeslice64(et, ptr, len64)
    85  
    86  	// Check that underlying array doesn't straddle multiple heap objects.
    87  	// unsafeslice64 has already checked for overflow.
    88  	if checkptrStraddles(ptr, uintptr(len64)*et.Size_) {
    89  		throw("checkptr: unsafe.Slice result straddles multiple allocations")
    90  	}
    91  }
    92  
    93  func panicunsafeslicelen() {
    94  	// This is called only from compiler-generated code, so we can get the
    95  	// source of the panic.
    96  	panicunsafeslicelen1(sys.GetCallerPC())
    97  }
    98  
    99  //go:yeswritebarrierrec
   100  func panicunsafeslicelen1(pc uintptr) {
   101  	panicCheck1(pc, "unsafe.Slice: len out of range")
   102  	panic(errorString("unsafe.Slice: len out of range"))
   103  }
   104  
   105  func panicunsafeslicenilptr() {
   106  	// This is called only from compiler-generated code, so we can get the
   107  	// source of the panic.
   108  	panicunsafeslicenilptr1(sys.GetCallerPC())
   109  }
   110  
   111  //go:yeswritebarrierrec
   112  func panicunsafeslicenilptr1(pc uintptr) {
   113  	panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero")
   114  	panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
   115  }
   116  
   117  //go:linkname reflect_unsafeslice reflect.unsafeslice
   118  func reflect_unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
   119  	unsafeslice(et, ptr, len)
   120  }
   121  

View as plain text