aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/syscall/exec_windows.go17
-rw-r--r--src/syscall/exec_windows_test.go73
2 files changed, 87 insertions, 3 deletions
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index 0ddc240a56..7b73cf1f6f 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -243,6 +243,7 @@ type SysProcAttr struct {
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
@@ -312,18 +313,22 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
}
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)
+ err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &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(_STARTUPINFOEXW)
- si.ProcThreadAttributeList, err = newProcThreadAttributeList(1)
+ si.ProcThreadAttributeList, err = newProcThreadAttributeList(2)
if err != nil {
return 0, 0, err
}
@@ -334,6 +339,12 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
si.Flags |= STARTF_USESHOWWINDOW
si.ShowWindow = SW_HIDE
}
+ if sys.ParentProcess != 0 {
+ err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, uintptr(unsafe.Pointer(&sys.ParentProcess)), unsafe.Sizeof(sys.ParentProcess), 0, nil)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
si.StdInput = fd[0]
si.StdOutput = fd[1]
si.StdErr = fd[2]
diff --git a/src/syscall/exec_windows_test.go b/src/syscall/exec_windows_test.go
index eda1d36877..8a1c2ceaae 100644
--- a/src/syscall/exec_windows_test.go
+++ b/src/syscall/exec_windows_test.go
@@ -5,8 +5,14 @@
package syscall_test
import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
"syscall"
"testing"
+ "time"
)
func TestEscapeArg(t *testing.T) {
@@ -41,3 +47,70 @@ func TestEscapeArg(t *testing.T) {
}
}
}
+
+func TestChangingProcessParent(t *testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") == "parent" {
+ // in parent process
+
+ // Parent does nothign. It is just used as a parent of a child process.
+ time.Sleep(time.Minute)
+ os.Exit(0)
+ }
+
+ if os.Getenv("GO_WANT_HELPER_PROCESS") == "child" {
+ // in child process
+ dumpPath := os.Getenv("GO_WANT_HELPER_PROCESS_FILE")
+ if dumpPath == "" {
+ fmt.Fprintf(os.Stderr, "Dump file path cannot be blank.")
+ os.Exit(1)
+ }
+ err := os.WriteFile(dumpPath, []byte(fmt.Sprintf("%d", os.Getppid())), 0644)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing dump file: %v", err)
+ os.Exit(2)
+ }
+ os.Exit(0)
+ }
+
+ // run parent process
+
+ parent := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent")
+ parent.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=parent")
+ err := parent.Start()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ parent.Process.Kill()
+ parent.Wait()
+ }()
+
+ // run child process
+
+ const _PROCESS_CREATE_PROCESS = 0x0080
+ const _PROCESS_DUP_HANDLE = 0x0040
+ childDumpPath := filepath.Join(t.TempDir(), "ppid.txt")
+ ph, err := syscall.OpenProcess(_PROCESS_CREATE_PROCESS|_PROCESS_DUP_HANDLE|syscall.PROCESS_QUERY_INFORMATION,
+ false, uint32(parent.Process.Pid))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer syscall.CloseHandle(ph)
+
+ child := exec.Command(os.Args[0], "-test.run=TestChangingProcessParent")
+ child.Env = append(os.Environ(),
+ "GO_WANT_HELPER_PROCESS=child",
+ "GO_WANT_HELPER_PROCESS_FILE="+childDumpPath)
+ child.SysProcAttr = &syscall.SysProcAttr{ParentProcess: ph}
+ childOutput, err := child.CombinedOutput()
+ if err != nil {
+ t.Errorf("child failed: %v: %v", err, string(childOutput))
+ }
+ childOutput, err = ioutil.ReadFile(childDumpPath)
+ if err != nil {
+ t.Fatalf("reading child ouput failed: %v", err)
+ }
+ if got, want := string(childOutput), fmt.Sprintf("%d", parent.Process.Pid); got != want {
+ t.Fatalf("child output: want %q, got %q", want, got)
+ }
+}