Skip to content

exec.*Cmd.Wait fails with ERROR_INVALID_PARAMETER on windows #1460

@alexbrainman

Description

@alexbrainman
What steps will reproduce the problem?

Compile and run this program:

package main

import "syscall"
import "exec"
import "log"

func main() {
    p, err := exec.Run("cmd", []string{"/c", "dir"}, nil, "",
        exec.DevNull, exec.DevNull, exec.DevNull)
    if err != nil {
        log.Exit(err)
    }
    syscall.Sleep(3000000000)
    _, err = p.Wait(0)
    if err != nil {
        log.Exitf("Wait failed with error \"%s\"\n", err.String())
    }
    println("Success.")
}

What is the expected output? 
Success.

What do you see instead?
2011/02/01 14:17:47 Wait failed with error "wait: The parameter is incorrect."

Please use labels and text to provide additional information.

The problem is pid is not reliable process identifier on windows, must use handle
returned by windows api CreateProcess instead. But current os interface doesn't support
that. To demonstrate, this is what is happening under covers for correspondent os
functions on Windows:

os.ForkExec(...) (pid):
handle, pid = CreateProcess(...)    // create process
CloseHandle(handle)         // close handle, we're not going to use it
return pid

os.Wait(pid) (rc):
handle := OpenProcess(pid)      // find our process, convert pid into handle
WaitForSingleObject(handle)     // wait for process to end
rc = GetExitCodeProcess(handle)     // get exit code
CloseHandle(handle)         // done with our process
return rc

Under certain conditions (on Windows 2000 much more often then others), OpenProcess
fails, because pid was reused or whatever, therefore we can't continue to retrieve exit
code.

The interface should be:

os.ForkExec(...) (handle, pid):
handle, pid = CreateProcess(...)    // create process
return handle, pid

os.Wait(handle) (rc):
WaitForSingleObject(handle)     // wait for process to end
rc = GetExitCodeProcess(handle)     // get exit code
return rc

Close process handle once done:
CloseHandle(handle)         // done with our process

This can be accommodated if we introduce os.Process structure to hide all os specific
implementation details. There is an issue
https://golang.org/issue/1004 about it. But I couldn't reproduce the
problem on non Windows 2000 os. Now, thanks to mattn, we've got a test case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions