diff --git a/windows/env_windows.go b/windows/env_windows.go index f482a9fa..07511e14 100644 --- a/windows/env_windows.go +++ b/windows/env_windows.go @@ -8,7 +8,6 @@ package windows import ( "syscall" - "unicode/utf16" "unsafe" ) @@ -40,17 +39,11 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) { defer DestroyEnvironmentBlock(block) blockp := uintptr(unsafe.Pointer(block)) for { - entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:] - for i, v := range entry { - if v == 0 { - entry = entry[:i] - break - } - } + entry := UTF16PtrToString((*uint16)(unsafe.Pointer(blockp)), (1<<30)-1) if len(entry) == 0 { break } - env = append(env, string(utf16.Decode(entry))) + env = append(env, entry) blockp += 2 * (uintptr(len(entry)) + 1) } return env, nil diff --git a/windows/security_windows.go b/windows/security_windows.go index 194a5eba..b0fecd50 100644 --- a/windows/security_windows.go +++ b/windows/security_windows.go @@ -1230,7 +1230,7 @@ func (sd *SECURITY_DESCRIPTOR) String() string { return "" } defer LocalFree(Handle(unsafe.Pointer(sddl))) - return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(sddl))[:strLen:strLen]) + return UTF16PtrToString(sddl, int(strLen)) } // ToAbsolute converts a self-relative security descriptor into an absolute one. diff --git a/windows/svc/mgr/config.go b/windows/svc/mgr/config.go index 8431edbe..9fee0ef5 100644 --- a/windows/svc/mgr/config.go +++ b/windows/svc/mgr/config.go @@ -50,7 +50,7 @@ func toString(p *uint16) string { if p == nil { return "" } - return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:]) + return windows.UTF16PtrToString(p, 4096) } func toStringSlice(ps *uint16) []string { diff --git a/windows/svc/mgr/mgr.go b/windows/svc/mgr/mgr.go index 4149533f..edc3a46f 100644 --- a/windows/svc/mgr/mgr.go +++ b/windows/svc/mgr/mgr.go @@ -73,7 +73,7 @@ func (m *Mgr) LockStatus() (*LockStatus, error) { status := &LockStatus{ IsLocked: lockStatus.IsLocked != 0, Age: time.Duration(lockStatus.LockDuration) * time.Second, - Owner: windows.UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(lockStatus.LockOwner))[:]), + Owner: toString(lockStatus.LockOwner), } return status, nil } @@ -204,7 +204,7 @@ func (m *Mgr) ListServices() ([]string, error) { services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned:servicesReturned] var names []string for _, s := range services { - name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:]) + name := toString(s.ServiceName) names = append(names, name) } return names, nil diff --git a/windows/svc/service.go b/windows/svc/service.go index f0d7ddcd..b0e16296 100644 --- a/windows/svc/service.go +++ b/windows/svc/service.go @@ -224,10 +224,10 @@ const ( func (s *service) run() { s.goWaits.Wait() s.h = windows.Handle(ssHandle) - argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc:sArgc] + argv := (*[100]*uint16)(unsafe.Pointer(sArgv))[:sArgc:sArgc] args := make([]string, len(argv)) for i, a := range argv { - args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:]) + args[i] = windows.UTF16PtrToString(a, 1<<20) } cmdsToHandler := make(chan ChangeRequest) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index b3e55035..0cd000d8 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -117,6 +117,25 @@ func UTF16PtrFromString(s string) (*uint16, error) { return &a[0], nil } +// UTF16PtrToString is like UTF16ToString, but takes *uint16 +// as a parameter instead of []uint16. +// max is how many times p can be advanced looking for the null terminator. +// If max is hit, the string is truncated at that point. +func UTF16PtrToString(p *uint16, max int) string { + if p == nil { + return "" + } + // Find NUL terminator. + end := unsafe.Pointer(p) + n := 0 + for *(*uint16)(end) != 0 && n < max { + end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) + n++ + } + s := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:n:n] + return string(utf16.Decode(s)) +} + func Getpagesize() int { return 4096 } // NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention. @@ -1383,7 +1402,7 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e return "", err } defer CoTaskMemFree(unsafe.Pointer(p)) - return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil + return UTF16PtrToString(p, (1<<30)-1), nil } // RtlGetVersion returns the version of the underlying operating system, ignoring