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 }