kernel32.go (2137B)
1 //go:build windows 2 3 package kernel32 4 5 import ( 6 "sync/atomic" 7 "syscall" 8 "unsafe" 9 10 "golang.org/x/sys/windows" 11 ) 12 13 type ( 14 heapHandle = uintptr 15 win32Error uint32 16 heapFlags uint32 17 ) 18 19 const ( 20 heapNone heapFlags = 0 21 heapZeroMemory heapFlags = 8 // The allocated memory will be initialized to zero. 22 ) 23 24 var ( 25 libKernel32 = windows.NewLazySystemDLL("kernel32.dll") 26 27 pHeapFree uintptr 28 pHeapAlloc uintptr 29 pGetProcessHeap uintptr 30 31 hHeap heapHandle 32 ) 33 34 func init() { 35 hHeap, _ = getProcessHeap() 36 } 37 38 // Malloc allocates the given amount of bytes in the heap 39 func Malloc(size uintptr) unsafe.Pointer { 40 return heapAlloc(hHeap, heapZeroMemory, size) 41 } 42 43 // Free releases the given unsafe pointer from the heap 44 func Free(inst unsafe.Pointer) { 45 _, _ = heapFree(hHeap, heapNone, inst) 46 } 47 48 // https://docs.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc 49 func heapAlloc(hHeap heapHandle, dwFlags heapFlags, dwBytes uintptr) unsafe.Pointer { 50 addr := getProcAddr(&pHeapAlloc, libKernel32, "HeapAlloc") 51 allocatedPtr, _, _ := syscall.SyscallN(addr, hHeap, uintptr(dwFlags), dwBytes) 52 // Since this pointer is allocated in the heap by Windows, it will never be 53 // GCd by Go, so this is a safe operation. 54 // But linter thinks it is not (probably because we are not using CGO) and fails. 55 return unsafe.Pointer(allocatedPtr) //nolint:gosec,govet 56 } 57 58 // https://docs.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree 59 func heapFree(hHeap heapHandle, dwFlags heapFlags, lpMem unsafe.Pointer) (bool, win32Error) { 60 addr := getProcAddr(&pHeapFree, libKernel32, "HeapFree") 61 ret, _, err := syscall.SyscallN(addr, hHeap, uintptr(dwFlags), uintptr(lpMem)) 62 return ret == 0, win32Error(err) 63 } 64 65 func getProcessHeap() (heapHandle, win32Error) { 66 addr := getProcAddr(&pGetProcessHeap, libKernel32, "GetProcessHeap") 67 ret, _, err := syscall.SyscallN(addr) 68 return ret, win32Error(err) 69 } 70 71 func getProcAddr(pAddr *uintptr, lib *windows.LazyDLL, procName string) uintptr { 72 addr := atomic.LoadUintptr(pAddr) 73 if addr == 0 { 74 addr = lib.NewProc(procName).Addr() 75 atomic.StoreUintptr(pAddr, addr) 76 } 77 return addr 78 }