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  }