github.com/gabe-lee/unsafer@v0.1.1/unsafer.go (about)

     1  package unsafer
     2  
     3  import (
     4  	"unsafe"
     5  )
     6  
     7  /*********************************************************************************
     8  	THE FOLLOWING TYPES AND CONSTANTS ARE ANALOGOUS WITH GO'S INTERNAL SOURCE CODE
     9  	AND SHOULD BE TREATED AS SUCH FOR LICENSING AND REDISTRIBUTION PURPOSES
    10  *********************************************************************************/
    11  
    12  // Size of a pointer for the target architecture
    13  //
    14  // Unsafety Rating: ☆☆☆☆☆ (perfectly safe)
    15  const SystemPointerSize = 4 << (^uintptr(0) >> 63)
    16  
    17  // Internal structure of a string
    18  //
    19  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
    20  type StringInternal struct {
    21  	Data unsafe.Pointer // Pointer to beginning of string data
    22  	Len  int            // Length of data in bytes
    23  }
    24  
    25  // Internal structure of a slice
    26  //
    27  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
    28  type SliceInternal struct {
    29  	Data unsafe.Pointer // Pointer to beginning of slice data
    30  	Len  int            // Length of slice
    31  	Cap  int            // Capacity of slice
    32  }
    33  
    34  // Additional info about the type
    35  type TypeFlag uint8
    36  
    37  const (
    38  	TFlagUncommon      TypeFlag = 1 << 0 // ??
    39  	TFlagExtraStar     TypeFlag = 1 << 1 // Whether the Name field has an extra superfluous star in front of it
    40  	TFlagNamed         TypeFlag = 1 << 2 // Type has a defined name
    41  	TFlagRegularMemory TypeFlag = 1 << 3 // Whether the type can be treated in its entirety as contiguous block of Size bytes
    42  )
    43  
    44  type NameOffset int32 // int32 offset from specific TypeInternal pointer to its string name
    45  type TypeOffset int32 // int32 offset from specific TypeInternal pointer to the type that is a POINTER-TO the type
    46  
    47  const (
    48  	NameExported                       byte = 1
    49  	NameFollowedByTagData              byte = 2
    50  	TagDataFollowedByPkgPathNameOffset byte = 4
    51  )
    52  
    53  // Encoded type name with additional data.
    54  //
    55  // First byte has flags describing the name, followed by varint-encoded length,
    56  // followed by the name itself.
    57  //
    58  // If NameFollowedByTagData is set, the name is followed by
    59  // a varint-encoded length followed by the tag data itself.
    60  //
    61  // If TagDataFollowedByPkgPathNameOffset is set, tag data is followed by a NameOffset
    62  // (int32)
    63  //
    64  // Unsafety Rating: ★★★☆☆ (clearly unsafe)
    65  type EncodedName struct {
    66  	Bytes *byte // pointer to first byte of encoded name
    67  }
    68  
    69  // Internals of Go's type system for most types
    70  //
    71  // Unsafety Rating: ★★☆☆☆ (use caution)
    72  type TypeInternal struct {
    73  	Size        uintptr                                   // How large the type is. Does not include the size of any data POINTED TO by this type or any fields/elements of this type
    74  	PtrData     uintptr                                   // size of memory prefix holding all pointers
    75  	Hash        uint32                                    // Precomputed hash of this type
    76  	TypeFlags   TypeFlag                                  // Additional type data
    77  	Align       uint8                                     // Byte alignment of a variable of this type
    78  	FieldAlign  uint8                                     // Byte alignment of a struct field of this type
    79  	kind        Kind                                      // Base category this type falls under
    80  	Equals      func(unsafe.Pointer, unsafe.Pointer) bool // Function for comparing equality between two variables of this type
    81  	GCData      *byte                                     // GarbageCollectionData: for the truly insane, see src/runtime/mbitmap.go
    82  	Name        NameOffset                                // Offset to the plain-text name for this type as a string
    83  	Pointertype TypeOffset                                // Offset to the type that is a POINTER-TO this type (*T)
    84  }
    85  
    86  // Flags for special map states
    87  type MapFlag uint8
    88  
    89  const (
    90  	BeingUsedByIterator    MapFlag = 1 // An iterator may be using the currrent buckets
    91  	OldBeingUsedByIterator MapFlag = 2 // An iterator may be using the old buckets
    92  	BeingWrittenTo         MapFlag = 4 // A goroutine is writing to the map
    93  	GrowingToSameSize      MapFlag = 8 // The current grow operation is growing to a map of the same size
    94  )
    95  
    96  // Internal structure of a map
    97  //
    98  // Unsafety Rating: ★★☆☆☆ (use caution)
    99  type MapInternal struct {
   100  	Count          int            // Number of Key-Value pairs currently active
   101  	Flags          MapFlag        // Flags for special map states
   102  	NumBucketsLog2 uint8          // Log (base 2) of the number of buckets
   103  	NumOverflow    uint16         // (Approximate) Number of overflow buckets
   104  	HashSeed       uint32         // Seed for the hashing algorithm
   105  	Buckets        unsafe.Pointer // Bucket array with length = NumBucketsLog2^2, may be nil if Count == 0
   106  	OldBuckets     unsafe.Pointer // Old bucket array of half the current size, only non-nil when in the process of growing
   107  	NumEvacuated   uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
   108  	MapOverflow    *MapOverflow   // Holds pointers to overflow buckets for map types that require them
   109  }
   110  
   111  // Holds pointers to overflow buckets for map types that require them
   112  //
   113  // Unsafety Rating: ★★★☆☆ (clearly unsafe)
   114  type MapOverflow struct {
   115  	OverflowBuckets    *[]*BucketInternal // Pointer to master list of current overflow buckets to keep them alive
   116  	OldOverflowBuckets *[]*BucketInternal // Pointer to master list of old overflow buckets to keep them alive
   117  	NextOverflowBucket *BucketInternal    // Next free overflow bucket
   118  }
   119  
   120  // How many Key/Value pairs a bucket can hold
   121  //
   122  // Unsafety Rating: ☆☆☆☆☆ (perfectly safe)
   123  const BucketSize = 8
   124  
   125  // The offset from a bucket's location in memory to where its Key/Value pairs begin
   126  //
   127  // Unsafety Rating: ★★★★☆ (highly dangerous)
   128  const BucketDataStart = unsafe.Offsetof(struct {
   129  	b BucketInternal
   130  	v int64
   131  }{}.v)
   132  
   133  const (
   134  	LastEmptyCell         uint8 = 0 // Special TopHash: This cell is empty, and there are no more non-empty cells after this one.
   135  	EmptyCell             uint8 = 1 // Special TopHash: This cell is empty
   136  	EvacuatedToFirstHalf  uint8 = 2 // Special TopHash: Key/Value pair is valid, but it has been evacuated to the first half of a larger bucket
   137  	EvacuatedToSecondHalf uint8 = 3 // Special TopHash: Key/Value pair is valid, but it has been evacuated to the second half of a larger bucket
   138  	EvacuatedAndEmpty     uint8 = 4 // Special TopHash: This cell is empty and the entire bucket is evacuated
   139  	MinimumTopHash        uint8 = 5 // Minimum TopHash value for a normal, non-evacuated cell
   140  )
   141  
   142  // Internals of a map bucket.
   143  // Immediately following the bucket's place in memory are 8(BucketSize) keys then 8(BucketSize) values,
   144  // followed by a pointer to an overflow bucket
   145  //
   146  // Unsafety Rating: ★★★☆☆ (clearly unsafe)
   147  type BucketInternal struct {
   148  	// Normally holds the top byte of the hash value for each key in the bucket,
   149  	// or a special value for empty cells or evacuation state.
   150  	TopHash [BucketSize]uint8
   151  }
   152  
   153  // Internals of an interface that defines methods
   154  //
   155  // Unsafety Rating: ★★☆☆☆ (use caution)
   156  type InterfaceInternal struct {
   157  	IDescription *InterfaceDescription // Description of the interface
   158  	Data         unsafe.Pointer        // Pointer to the concrete data
   159  }
   160  
   161  // Description of an interface that defines methods
   162  //
   163  // Unsafety Rating: ★★☆☆☆ (use caution)
   164  type InterfaceDescription struct {
   165  	IType *ITypeInternal // The type of the interface definition itself
   166  	Type  *TypeInternal  // The type of the concrete data held by the interface
   167  	Hash  uint32         // Same as Type.Hash
   168  	_     [4]byte        // Padding
   169  	// Pointers to the concrete functions the interface describes.
   170  	// The size of this array is variable, contrary to what is listed.
   171  	// If first index == 0, Type does not implement IType
   172  	FunctionPointers [1]uintptr
   173  }
   174  
   175  // TypeInternal wrapper for interfaces
   176  //
   177  // Unsafety Rating: ★★☆☆☆ (use caution)
   178  type ITypeInternal struct {
   179  	Type         TypeInternal      // Basic type data for the interface
   180  	PackagePath  EncodedName       // An EncodedName describing the package path of the interface
   181  	MethodHeader []InterfaceMethod // A list of method types the interface has
   182  }
   183  
   184  // Type describing the type of a method on an interface
   185  //
   186  // Unsafety Rating: ★★☆☆☆ (use caution)
   187  type InterfaceMethod struct {
   188  	Name NameOffset // Offset pointing to the name of the function
   189  	Type TypeOffset // Offset pointing to the type of the function
   190  }
   191  
   192  // Internals of 'any' (also known as the empty interface, interface{})
   193  //
   194  // Unsafety Rating: ★★☆☆☆ (use caution)
   195  type AnyInternal struct {
   196  	Type *TypeInternal  // Pointer to the TYPE of the concrete data
   197  	Data unsafe.Pointer // Pointer to the concrete data
   198  }
   199  
   200  type Kind uint8
   201  
   202  const (
   203  	KindBool Kind = 1 + iota
   204  	KindInt
   205  	KindInt8
   206  	KindInt16
   207  	KindInt32
   208  	KindInt64
   209  	KindUint
   210  	KindUint8
   211  	KindUint16
   212  	KindUint32
   213  	KindUint64
   214  	KindUintptr
   215  	KindFloat32
   216  	KindFloat64
   217  	KindComplex64
   218  	KindComplex128
   219  	KindArray
   220  	KindChan
   221  	KindFunc
   222  	KindInterface
   223  	KindMap
   224  	KindPointer
   225  	KindSlice
   226  	KindString
   227  	KindStruct
   228  	KindUnsafePointer
   229  
   230  	KindDirectIface Kind = 1 << 5       // Whether the type is stored directly in an interface
   231  	KindGCProg      Kind = 1 << 6       // Whether the value pointed to by TypeInternal.GCData is a GCProgram
   232  	KindMask        Kind = (1 << 5) - 1 // Mask for base kinds without special flags
   233  )
   234  
   235  // NoEscape hides a pointer from escape analysis. NoEscape is
   236  // the identity function but escape analysis doesn't think the
   237  // output depends on the input.  NoEscape is inlined and currently
   238  // compiles down to zero instructions.
   239  //
   240  // Unsafety Rating: ★★★☆☆ (clearly unsafe)
   241  //go:nosplit
   242  func NoEscape(p unsafe.Pointer) unsafe.Pointer {
   243  	x := uintptr(p)
   244  	return unsafe.Pointer(x ^ 0)
   245  }
   246  
   247  /*********************************************************************************
   248  	THE FOLLOWING FUNCTIONS AND TYPES ARE ADDED BY THE AUTHOR TO MAKE USE OF THE
   249  	ABOVE TYPES IN NEW, INTERESTING, AND POSSIBLY UNSAFER WAYS, LICENSED UNDER
   250  	THE PERMISIVE BSD 2-CLAUSE LICENSE.
   251  *********************************************************************************/
   252  
   253  // Return the unique type pointer of the supplied value.
   254  // This is THE definitive address where the type's definition resides,
   255  // and will not change for the duration of the program.
   256  //
   257  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
   258  func GetTypePointer(t any) (pointer uintptr) {
   259  	tt := (*AnyInternal)(unsafe.Pointer(&t))
   260  	return uintptr(unsafe.Pointer(tt.Type))
   261  }
   262  
   263  // Return the unique type hash of the supplied value.
   264  // In most cases the hash is enough to uniqely identify a type, but
   265  // collisions may exists. This value will not change
   266  // for a given type for the duration of the program.
   267  //
   268  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
   269  func GetTypeHash(t any) (hash uint32) {
   270  	tt := (*AnyInternal)(unsafe.Pointer(&t))
   271  	return tt.Type.Hash
   272  }
   273  
   274  // Get the basic kind of variable this type embodies
   275  //
   276  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
   277  func GetKind(t any) Kind {
   278  	tt := (*AnyInternal)(unsafe.Pointer(&t))
   279  	return tt.Type.kind & KindMask
   280  }
   281  
   282  // Tell Go that t1 is *actually* of the same type as t2, as in
   283  // a type assertion on the returned 'any' value will resolve to
   284  // the same type as t2 using the data pointed to by t1.
   285  //
   286  // Unsafety Rating: ★★★★☆ (highly dangerous)
   287  func Spoof(t1 any, t2 any) any {
   288  	tt := (*AnyInternal)(unsafe.Pointer(&t1))
   289  	tt.Type = (*TypeInternal)(unsafe.Pointer(GetTypePointer(t2)))
   290  	return t1
   291  }
   292  
   293  // Invent an 'any' value from the memory pointed to by data,
   294  // and the type located at typePointer. Use GetTypePointer(t any) to
   295  // find type pointer addresses.
   296  //
   297  // Unsafety Rating: ★★★★★ (C U R S E D)
   298  func Invent(data unsafe.Pointer, typePointer uintptr) (value any) {
   299  	a := (*AnyInternal)(unsafe.Pointer(&value))
   300  	a.Data = data
   301  	a.Type = (*TypeInternal)(unsafe.Pointer(typePointer))
   302  	return value
   303  }
   304  
   305  // Return a string that mirrors the data in slice,
   306  // with a fixed length matching the length of the slice at time of calling.
   307  //
   308  // Any changes to the bytes in range slice[0:lenAtCallTime] will be reflected by the string
   309  // in future reads.
   310  //
   311  // Assignment to the resulting string, assignment to the byte slice,
   312  // or an append call that reallocates the byte slice
   313  // will break the relationship, however since string still has pointer to
   314  // old data it will persist in the state it was in prior to breaking.
   315  //
   316  // Unsafety Rating: ★☆☆☆☆ (relatively safe)
   317  func ByteString(slice []byte) string {
   318  	return *(*string)(unsafe.Pointer(&slice))
   319  }