From c8ea6b0cbc9ffb7927e068f279c46cb342d0c956 Mon Sep 17 00:00:00 2001 From: Roman Mazur Date: Wed, 17 May 2023 22:45:36 +0200 Subject: [PATCH] windows: fix EnumProcesses to pass the correct array size Implementation generated directly with mkwinsyscall has a wrong assumption about the expected value for PIDs buffer size. This change adds some small manual code that converts the input slice length to the number of bytes of the array backing the slice. A test is also added. It fails with the previous implementation. Fixes golang/go#60223 Change-Id: I5e2414acb29c6c949e5e6acd328043f8a8883887 Reviewed-on: https://go-review.googlesource.com/c/sys/+/495995 Commit-Queue: Quim Muntal TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills Run-TryBot: Quim Muntal Reviewed-by: Quim Muntal Reviewed-by: Heschi Kreinick --- windows/syscall_windows.go | 13 ++++++++++++- windows/syscall_windows_test.go | 22 ++++++++++++++++++++++ windows/zsyscall_windows.go | 8 ++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 3723b2c22..964590075 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -405,7 +405,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys VerQueryValue(block unsafe.Pointer, subBlock string, pointerToBufferPointer unsafe.Pointer, bufSize *uint32) (err error) = version.VerQueryValueW // Process Status API (PSAPI) -//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses +//sys enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses //sys EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) = psapi.EnumProcessModules //sys EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) = psapi.EnumProcessModulesEx //sys GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) = psapi.GetModuleInformation @@ -1354,6 +1354,17 @@ func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { return syscall.EWINDOWS } +func EnumProcesses(processIds []uint32, bytesReturned *uint32) error { + // EnumProcesses syscall expects the size parameter to be in bytes, but the code generated with mksyscall uses + // the length of the processIds slice instead. Hence, this wrapper function is added to fix the discrepancy. + var p *uint32 + if len(processIds) > 0 { + p = &processIds[0] + } + size := uint32(len(processIds) * 4) + return enumProcesses(p, size, bytesReturned) +} + func Getpid() (pid int) { return int(GetCurrentProcessId()) } func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) { diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 42c01fc96..81050d337 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -717,6 +717,28 @@ func TestWinVerifyTrust(t *testing.T) { } +func TestEnumProcesses(t *testing.T) { + var ( + pids [2]uint32 + outSize uint32 + ) + err := windows.EnumProcesses(pids[:], &outSize) + if err != nil { + t.Fatalf("unable to enumerate processes: %v", err) + } + + // Regression check for go.dev/issue/60223 + if outSize != 8 { + t.Errorf("unexpected bytes returned: %d", outSize) + } + // Most likely, this should be [0, 4]. + // 0 is the system idle pseudo-process. 4 is the initial system process ID. + // This test expects that at least one of the PIDs is not 0. + if pids[0] == 0 && pids[1] == 0 { + t.Errorf("all PIDs are 0") + } +} + func TestProcessModules(t *testing.T) { process, err := windows.GetCurrentProcess() if err != nil { diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index a81ea2c70..566dd3e31 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -3516,12 +3516,8 @@ func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *u return } -func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) { - var _p0 *uint32 - if len(processIds) > 0 { - _p0 = &processIds[0] - } - r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(len(processIds)), uintptr(unsafe.Pointer(bytesReturned))) +func enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(processIds)), uintptr(nSize), uintptr(unsafe.Pointer(bytesReturned))) if r1 == 0 { err = errnoErr(e1) }