mirror of
https://github.com/golang/sys.git
synced 2026-02-08 03:36:03 +03:00
It turns out that the proc thread update function doesn't actually allocate new memory for its arguments and instead just copies the pointer values into the preallocated memory. Since we were allocating that memory as []byte, the garbage collector didn't scan it for pointers to Go allocations and freed them. We _could_ fix this by requiring that all users of this use runtime.KeepAlive for everything they pass to the update function, but that seems harder than necessary. Instead, we can just do the allocation as []unsafe.Pointer, which means the GC can operate as intended and not free these from beneath our feet. In order to ensure this remains true, we also add a test for this. Updates golang/go#44662. Change-Id: Iaa8b694a6682cc1876879632c7ba068e47b8666d Reviewed-on: https://go-review.googlesource.com/c/sys/+/297331 Trust: Jason A. Donenfeld <Jason@zx2c4.com> Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
133 lines
3.2 KiB
Go
133 lines
3.2 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Fork, exec, wait, etc.
|
|
|
|
package windows
|
|
|
|
import (
|
|
errorspkg "errors"
|
|
"unsafe"
|
|
)
|
|
|
|
// EscapeArg rewrites command line argument s as prescribed
|
|
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
|
// This function returns "" (2 double quotes) if s is empty.
|
|
// Alternatively, these transformations are done:
|
|
// - every back slash (\) is doubled, but only if immediately
|
|
// followed by double quote (");
|
|
// - every double quote (") is escaped by back slash (\);
|
|
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
|
// but only if there is space or tab inside s.
|
|
func EscapeArg(s string) string {
|
|
if len(s) == 0 {
|
|
return "\"\""
|
|
}
|
|
n := len(s)
|
|
hasSpace := false
|
|
for i := 0; i < len(s); i++ {
|
|
switch s[i] {
|
|
case '"', '\\':
|
|
n++
|
|
case ' ', '\t':
|
|
hasSpace = true
|
|
}
|
|
}
|
|
if hasSpace {
|
|
n += 2
|
|
}
|
|
if n == len(s) {
|
|
return s
|
|
}
|
|
|
|
qs := make([]byte, n)
|
|
j := 0
|
|
if hasSpace {
|
|
qs[j] = '"'
|
|
j++
|
|
}
|
|
slashes := 0
|
|
for i := 0; i < len(s); i++ {
|
|
switch s[i] {
|
|
default:
|
|
slashes = 0
|
|
qs[j] = s[i]
|
|
case '\\':
|
|
slashes++
|
|
qs[j] = s[i]
|
|
case '"':
|
|
for ; slashes > 0; slashes-- {
|
|
qs[j] = '\\'
|
|
j++
|
|
}
|
|
qs[j] = '\\'
|
|
j++
|
|
qs[j] = s[i]
|
|
}
|
|
j++
|
|
}
|
|
if hasSpace {
|
|
for ; slashes > 0; slashes-- {
|
|
qs[j] = '\\'
|
|
j++
|
|
}
|
|
qs[j] = '"'
|
|
j++
|
|
}
|
|
return string(qs[:j])
|
|
}
|
|
|
|
func CloseOnExec(fd Handle) {
|
|
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
|
}
|
|
|
|
// FullPath retrieves the full path of the specified file.
|
|
func FullPath(name string) (path string, err error) {
|
|
p, err := UTF16PtrFromString(name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
n := uint32(100)
|
|
for {
|
|
buf := make([]uint16, n)
|
|
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if n <= uint32(len(buf)) {
|
|
return UTF16ToString(buf[:n]), nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// NewProcThreadAttributeList allocates a new ProcThreadAttributeList, with the requested maximum number of attributes.
|
|
func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList, error) {
|
|
var size uintptr
|
|
err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
|
|
if err != ERROR_INSUFFICIENT_BUFFER {
|
|
if err == nil {
|
|
return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")
|
|
}
|
|
return nil, err
|
|
}
|
|
const psize = unsafe.Sizeof(uintptr(0))
|
|
// size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
|
|
al := (*ProcThreadAttributeList)(unsafe.Pointer(&make([]unsafe.Pointer, (size+psize-1)/psize)[0]))
|
|
err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return al, err
|
|
}
|
|
|
|
// Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
|
|
func (al *ProcThreadAttributeList) Update(attribute uintptr, flags uint32, value unsafe.Pointer, size uintptr, prevValue unsafe.Pointer, returnedSize *uintptr) error {
|
|
return updateProcThreadAttribute(al, flags, attribute, value, size, prevValue, returnedSize)
|
|
}
|
|
|
|
// Delete frees ProcThreadAttributeList's resources.
|
|
func (al *ProcThreadAttributeList) Delete() {
|
|
deleteProcThreadAttributeList(al)
|
|
}
|