diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 753a7937e1eabc7934d7ce0018df660d14b1b6bb..fd256ee000c3cb69165feeca151dc44dc4483149 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -151,7 +151,7 @@ var pkgDeps = map[string][]string{ "syscall/js": {"L0"}, "internal/oserror": {"L0"}, "internal/syscall/unix": {"L0", "syscall"}, - "internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"}, + "internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"}, "internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"}, "time": { // "L0" without the "io" package: diff --git a/src/internal/syscall/windows/reparse_windows.go b/src/internal/syscall/windows/reparse_windows.go index 610b733c4a9dc38096d531704b13ec1e9c9bc460..6e111392f09169d174f00f9d38c2d62538ca7832 100644 --- a/src/internal/syscall/windows/reparse_windows.go +++ b/src/internal/syscall/windows/reparse_windows.go @@ -60,8 +60,9 @@ type SymbolicLinkReparseBuffer struct { // Path returns path stored in rb. func (rb *SymbolicLinkReparseBuffer) Path() string { - p := (*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0])) - return syscall.UTF16ToString(p[rb.SubstituteNameOffset/2 : (rb.SubstituteNameOffset+rb.SubstituteNameLength)/2]) + n1 := rb.SubstituteNameOffset / 2 + n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2 + return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2]) } type MountPointReparseBuffer struct { @@ -83,6 +84,7 @@ type MountPointReparseBuffer struct { // Path returns path stored in rb. func (rb *MountPointReparseBuffer) Path() string { - p := (*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0])) - return syscall.UTF16ToString(p[rb.SubstituteNameOffset/2 : (rb.SubstituteNameOffset+rb.SubstituteNameLength)/2]) + n1 := rb.SubstituteNameOffset / 2 + n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2 + return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2]) } diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index 099e91ed68c9b4303e51fdb55d16bf6968e9fed2..dc641116baef421b2fa43c0455ca701ae0284041 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -7,9 +7,29 @@ package windows import ( "sync" "syscall" + "unicode/utf16" "unsafe" ) +// 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)) +} + const ( ERROR_SHARING_VIOLATION syscall.Errno = 32 ERROR_LOCK_VIOLATION syscall.Errno = 33 diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go index 28b0a65f665913b56516a1241b489e5117e061ce..544943278dc27378c6468d51d3d4ce84f10df0ea 100644 --- a/src/net/interface_windows.go +++ b/src/net/interface_windows.go @@ -58,7 +58,7 @@ func interfaceTable(ifindex int) ([]Interface, error) { if ifindex == 0 || ifindex == int(index) { ifi := Interface{ Index: int(index), - Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:]), + Name: windows.UTF16PtrToString(aa.FriendlyName, 10000), } if aa.OperStatus == windows.IfOperStatusUp { ifi.Flags |= FlagUp diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go index cb840ae2387989a56babb445df2e2ce0ca5e1228..7d5c9419566d8847a007d099005d730543ea7ba2 100644 --- a/src/net/lookup_windows.go +++ b/src/net/lookup_windows.go @@ -6,6 +6,7 @@ package net import ( "context" + "internal/syscall/windows" "os" "runtime" "syscall" @@ -233,7 +234,7 @@ func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) { defer syscall.DnsRecordListFree(r, 1) resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r) - cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + cname := windows.UTF16PtrToString(resolved, 256) return absDomainName([]byte(cname)), nil } @@ -277,7 +278,7 @@ func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) { mxs := make([]*MX, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) { v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0])) - mxs = append(mxs, &MX{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]))), v.Preference}) + mxs = append(mxs, &MX{absDomainName([]byte(windows.UTF16PtrToString(v.NameExchange, 256))), v.Preference}) } byPref(mxs).sort() return mxs, nil @@ -317,8 +318,8 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) { for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) { d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0])) s := "" - for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] { - s += syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:]) + for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount:d.StringCount] { + s += windows.UTF16PtrToString(v, 1<<20) } txts = append(txts, s) } @@ -343,7 +344,7 @@ func (*Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) ptrs := make([]string, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) { v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0])) - ptrs = append(ptrs, absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])))) + ptrs = append(ptrs, absDomainName([]byte(windows.UTF16PtrToString(v.Host, 256)))) } return ptrs, nil } diff --git a/src/os/env_windows.go b/src/os/env_windows.go index e8f647e7ac778e5a2deb82c0d9a226f9c599eace..b1b1ee4b3e67530a28d60b80644f09111390db08 100644 --- a/src/os/env_windows.go +++ b/src/os/env_windows.go @@ -23,16 +23,20 @@ func environForSysProcAttr(sys *syscall.SysProcAttr) (env []string, err error) { defer windows.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 - } + + // find NUL terminator + end := unsafe.Pointer(blockp) + for *(*uint16)(end) != 0 { + end = unsafe.Pointer(uintptr(end) + 2) } - if len(entry) == 0 { + + n := (uintptr(end) - uintptr(unsafe.Pointer(blockp))) / 2 + if n == 0 { + // environment block ends with empty string break } + + entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:n:n] env = append(env, string(utf16.Decode(entry))) blockp += 2 * (uintptr(len(entry)) + 1) } diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index 38293a0d285f46ed647db4e29450c5b96eca39b0..10503c595ff9713b99c1c5fa5c4736ec0906f5e5 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -6,11 +6,11 @@ package os import ( "errors" + "internal/syscall/windows" "runtime" "sync/atomic" "syscall" "time" - "unsafe" ) func (p *Process) wait() (ps *ProcessState, err error) { @@ -98,8 +98,7 @@ func findProcess(pid int) (p *Process, err error) { } func init() { - p := syscall.GetCommandLine() - cmd := syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(p))[:]) + cmd := windows.UTF16PtrToString(syscall.GetCommandLine(), 0xffff) if len(cmd) == 0 { arg0, _ := Executable() Args = []string{arg0} diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 651fe63b3fb4cfac6123d8dc0c427186377523be..8c141031434ec276d8b3e06616eb7d999f5dea29 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -263,7 +263,8 @@ func createMountPoint(link string, target *reparseData) error { buf.SubstituteNameLength = target.substituteName.length buf.PrintNameOffset = target.printName.offset buf.PrintNameLength = target.printName.length - copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:], target.pathBuf) + pbuflen := len(target.pathBuf) + copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf) var rdb _REPARSE_DATA_BUFFER rdb.header.ReparseTag = windows.IO_REPARSE_TAG_MOUNT_POINT @@ -356,7 +357,8 @@ func createSymbolicLink(link string, target *reparseData, isrelative bool) error if isrelative { buf.Flags = windows.SYMLINK_FLAG_RELATIVE } - copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:], target.pathBuf) + pbuflen := len(target.pathBuf) + copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:pbuflen:pbuflen], target.pathBuf) var rdb _REPARSE_DATA_BUFFER rdb.header.ReparseTag = syscall.IO_REPARSE_TAG_SYMLINK @@ -714,7 +716,7 @@ func TestReadStdin(t *testing.T) { if n > consoleSize { n = consoleSize } - n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n], s16) + n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n:n], s16) s16 = s16[n:] *read = uint32(n) t.Logf("read %d -> %d", toread, *read) diff --git a/src/os/user/lookup_windows.go b/src/os/user/lookup_windows.go index 7499f6a470ba0a9de187745085f6f575d4fe2e41..faaddd2341f16ea66519c67fbd8e9b62022cb10a 100644 --- a/src/os/user/lookup_windows.go +++ b/src/os/user/lookup_windows.go @@ -44,11 +44,7 @@ func lookupFullNameServer(servername, username string) (string, error) { } defer syscall.NetApiBufferFree(p) i := (*syscall.UserInfo10)(unsafe.Pointer(p)) - if i.FullName == nil { - return "", nil - } - name := syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(i.FullName))[:]) - return name, nil + return windows.UTF16PtrToString(i.FullName, 1024), nil } func lookupFullName(domain, username, domainAndUser string) (string, error) { @@ -165,14 +161,13 @@ func listGroupsForUsernameAndDomain(username, domain string) ([]string, error) { if entriesRead == 0 { return nil, fmt.Errorf("listGroupsForUsernameAndDomain: NetUserGetLocalGroups() returned an empty list for domain: %s, username: %s", domain, username) } - entries := (*[1024]windows.LocalGroupUserInfo0)(unsafe.Pointer(p0))[:entriesRead] + entries := (*[1024]windows.LocalGroupUserInfo0)(unsafe.Pointer(p0))[:entriesRead:entriesRead] var sids []string for _, entry := range entries { if entry.Name == nil { continue } - name := syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(entry.Name))[:]) - sid, err := lookupGroupName(name) + sid, err := lookupGroupName(windows.UTF16PtrToString(entry.Name, 1024)) if err != nil { return nil, err } diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go index db80d98a084d019832c52cce5a77126663951ecc..3a757596066b3b67e6535b78254393f7c7c14696 100644 --- a/src/syscall/security_windows.go +++ b/src/syscall/security_windows.go @@ -163,7 +163,7 @@ func (sid *SID) String() (string, error) { return "", e } defer LocalFree((Handle)(unsafe.Pointer(s))) - return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil + return utf16PtrToString(s, 256), nil } // Len returns the length, in bytes, of a valid security identifier sid. diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 992f6738ce29dfa656c303c2c7fe23370f2b1f7a..950c281e4db4fce2f66efd6f12cf4d986aacc0d2 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -57,6 +57,25 @@ func UTF16ToString(s []uint16) string { return string(utf16.Decode(s)) } +// 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)) +} + // StringToUTF16Ptr returns pointer to the UTF-16 encoding of // the UTF-8 string s, with a terminating NUL added. If s // contains a NUL byte this function panics instead of @@ -769,7 +788,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { for n < len(pp.Path) && pp.Path[n] != 0 { n++ } - bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n] + bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n:n] sa.Name = string(bytes) return sa, nil