summaryrefslogtreecommitdiff
path: root/libgo/go/syscall/exec_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/syscall/exec_windows.go')
-rw-r--r--libgo/go/syscall/exec_windows.go99
1 files changed, 80 insertions, 19 deletions
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 46cbd7567dd..18d15028c3d 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -7,6 +7,7 @@
package syscall
import (
+ "runtime"
"sync"
"unicode/utf16"
"unsafe"
@@ -235,13 +236,15 @@ type ProcAttr struct {
}
type SysProcAttr struct {
- HideWindow bool
- CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
- CreationFlags uint32
- Token Token // if set, runs new process in the security context represented by the token
- ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process
- ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process
- NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process
+ HideWindow bool
+ CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
+ CreationFlags uint32
+ Token Token // if set, runs new process in the security context represented by the token
+ ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process
+ ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process
+ NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process
+ AdditionalInheritedHandles []Handle // a list of additional handles, already marked as inheritable, that will be inherited by the new process
+ ParentProcess Handle // if non-zero, the new process regards the process given by this handle as its parent process, and AdditionalInheritedHandles, if set, should exist in this parent process
}
var zeroProcAttr ProcAttr
@@ -310,46 +313,104 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
}
}
- // Acquire the fork lock so that no other threads
- // create new fds that are not yet close-on-exec
- // before we fork.
- ForkLock.Lock()
- defer ForkLock.Unlock()
+ var maj, min, build uint32
+ rtlGetNtVersionNumbers(&maj, &min, &build)
+ isWin7 := maj < 6 || (maj == 6 && min <= 1)
+ // NT kernel handles are divisible by 4, with the bottom 3 bits left as
+ // a tag. The fully set tag correlates with the types of handles we're
+ // concerned about here. Except, the kernel will interpret some
+ // special handle values, like -1, -2, and so forth, so kernelbase.dll
+ // checks to see that those bottom three bits are checked, but that top
+ // bit is not checked.
+ isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 }
p, _ := GetCurrentProcess()
+ parentProcess := p
+ if sys.ParentProcess != 0 {
+ parentProcess = sys.ParentProcess
+ }
fd := make([]Handle, len(attr.Files))
for i := range attr.Files {
if attr.Files[i] > 0 {
- err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
+ destinationProcessHandle := parentProcess
+
+ // On Windows 7, console handles aren't real handles, and can only be duplicated
+ // into the current process, not a parent one, which amounts to the same thing.
+ if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) {
+ destinationProcessHandle = p
+ }
+
+ err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
if err != nil {
return 0, 0, err
}
- defer CloseHandle(Handle(fd[i]))
+ defer DuplicateHandle(parentProcess, fd[i], 0, nil, 0, false, DUPLICATE_CLOSE_SOURCE)
}
}
- si := new(StartupInfo)
+ si := new(_STARTUPINFOEXW)
+ si.ProcThreadAttributeList, err = newProcThreadAttributeList(2)
+ if err != nil {
+ return 0, 0, err
+ }
+ defer deleteProcThreadAttributeList(si.ProcThreadAttributeList)
si.Cb = uint32(unsafe.Sizeof(*si))
si.Flags = STARTF_USESTDHANDLES
if sys.HideWindow {
si.Flags |= STARTF_USESHOWWINDOW
si.ShowWindow = SW_HIDE
}
+ if sys.ParentProcess != 0 {
+ err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, unsafe.Pointer(&sys.ParentProcess), unsafe.Sizeof(sys.ParentProcess), nil, nil)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
si.StdInput = fd[0]
si.StdOutput = fd[1]
si.StdErr = fd[2]
- pi := new(ProcessInformation)
+ fd = append(fd, sys.AdditionalInheritedHandles...)
- flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT
+ // On Windows 7, console handles aren't real handles, so don't pass them
+ // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ for i := range fd {
+ if isLegacyWin7ConsoleHandle(fd[i]) {
+ fd[i] = 0
+ }
+ }
+
+ // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST
+ // to treat the entire list as empty, so remove NULL handles.
+ j := 0
+ for i := range fd {
+ if fd[i] != 0 {
+ fd[j] = fd[i]
+ j++
+ }
+ }
+ fd = fd[:j]
+
+ // Do not accidentally inherit more than these handles.
+ if len(fd) > 0 {
+ err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
+
+ pi := new(ProcessInformation)
+ flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
if sys.Token != 0 {
- err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi)
+ err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
} else {
- err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi)
+ err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
}
if err != nil {
return 0, 0, err
}
defer CloseHandle(Handle(pi.Thread))
+ runtime.KeepAlive(fd)
+ runtime.KeepAlive(sys)
return int(pi.ProcessId), uintptr(pi.Process), nil
}