github.com/primecitizens/pcz/std@v0.2.1/builtin/ptr/ptr.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2019 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package stdptr 9 10 import ( 11 "unsafe" 12 13 "github.com/primecitizens/pcz/std/core/abi" 14 "github.com/primecitizens/pcz/std/core/assert" 15 "github.com/primecitizens/pcz/std/core/num" 16 "github.com/primecitizens/pcz/std/core/thread" 17 ) 18 19 // OnStack reports whether the pointer points to somewhere of 20 // current goroutine's stack. 21 func OnStack(ptr uintptr) bool { 22 return thread.G().Stack.PointerOnStack(ptr) 23 } 24 25 // Cast casts numeric pointer value to *R 26 // 27 //go:nosplit 28 func Cast[T any, Ptr num.Pointer](p Ptr) *T { 29 return (*T)(unsafe.Pointer(p)) 30 } 31 32 // Assign value of type T to the address: *(base+offset) = v 33 // 34 //go:nosplit 35 func Assign[T any, Ptr num.Pointer](base Ptr, offset uintptr, v T) { 36 *(*T)(unsafe.Pointer(uintptr(base) + offset)) = v 37 } 38 39 // Add adds offset off to p. 40 // 41 //go:nosplit 42 func Add[T any, O num.Integer](p *T, off O) *T { 43 return (*T)(unsafe.Add(unsafe.Pointer(p), off)) 44 } 45 46 func CheckAlignment(p unsafe.Pointer, elem *abi.Type, n uintptr) { 47 // nil pointer is always suitably aligned (#47430). 48 if p == nil { 49 return 50 } 51 52 // Check that (*[n]elem)(p) is appropriately aligned. 53 // Note that we allow unaligned pointers if the types they point to contain 54 // no pointers themselves. See issue 37298. 55 // TODO(mdempsky): What about fieldAlign? 56 if elem.PtrBytes != 0 && uintptr(p)&(uintptr(elem.Align_)-1) != 0 { 57 assert.Throw("checkptr: misaligned pointer conversion") 58 } 59 60 // Check that (*[n]elem)(p) doesn't straddle multiple heap objects. 61 // TODO(mdempsky): Fix #46938 so we don't need to worry about overflow here. 62 if CheckptrStraddles(p, n*elem.Size_) { 63 assert.Throw("checkptr: converted pointer straddles multiple allocations") 64 } 65 } 66 67 // CheckptrStraddles reports whether the first size-bytes of memory 68 // addressed by ptr is known to straddle more than one Go allocation. 69 func CheckptrStraddles(ptr unsafe.Pointer, size uintptr) bool { 70 if size <= 1 { 71 return false 72 } 73 74 // Check that add(ptr, size-1) won't overflow. This avoids the risk 75 // of producing an illegal pointer value (assuming ptr is legal). 76 if uintptr(ptr) >= -(size - 1) { 77 return true 78 } 79 end := unsafe.Add(ptr, size-1) 80 81 // TODO(mdempsky): Detect when [ptr, end] contains Go allocations, 82 // but neither ptr nor end point into one themselves. 83 84 return CheckptrBase(ptr) != CheckptrBase(end) 85 } 86 87 func CheckArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) { 88 // MinLegalPointer is the smallest possible legal pointer. 89 // This is the smallest possible architectural page size, 90 // since we assume that the first page is never mapped. 91 // 92 // This should agree with minZeroPage in the compiler. 93 const MinLegalPointer uintptr = 4096 94 95 if 0 < uintptr(p) && uintptr(p) < MinLegalPointer { 96 assert.Throw("checkptr: pointer arithmetic computed bad pointer value") 97 } 98 99 // Check that if the computed pointer p points into a heap 100 // object, then one of the original pointers must have pointed 101 // into the same object. 102 base := CheckptrBase(p) 103 if base == 0 { 104 return 105 } 106 107 for _, original := range originals { 108 if base == CheckptrBase(original) { 109 return 110 } 111 } 112 113 assert.Throw("checkptr: pointer arithmetic result points to invalid allocation") 114 } 115 116 // CheckptrBase returns the base address for the allocation containing 117 // the address p. 118 // 119 // Importantly, if p1 and p2 point into the same variable, then 120 // CheckptrBase(p1) == CheckptrBase(p2). However, the converse/inverse 121 // is not necessarily true as allocations can have trailing padding, 122 // and multiple variables may be packed into a single allocation. 123 func CheckptrBase(p unsafe.Pointer) uintptr { 124 // // stack 125 // if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi { 126 // // TODO(mdempsky): Walk the stack to identify the 127 // // specific stack frame or even stack object that p 128 // // points into. 129 // // 130 // // In the mean time, use "1" as a pseudo-address to 131 // // represent the stack. This is an invalid address on 132 // // all platforms, so it's guaranteed to be distinct 133 // // from any of the addresses we might return below. 134 // return 1 135 // } 136 // 137 // // heap (must check after stack because of #35068) 138 // if base, _, _ := findObject(uintptr(p), 0, 0); base != 0 { 139 // return base 140 // } 141 // 142 // // data or bss 143 // for _, datap := range activeModules() { 144 // if datap.data <= uintptr(p) && uintptr(p) < datap.edata { 145 // return datap.data 146 // } 147 // if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { 148 // return datap.bss 149 // } 150 // } 151 152 return 0 153 }