Skip to content

os/exec: Cmd.ProcessState field not always populated after (*Cmd.Run) returns #56002

@seh

Description

@seh

What version of Go are you using (go version)?

go version go1.19.1 darwin/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/seh/Library/Caches/go-build"
GOENV="/Users/seh/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/seh/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/seh/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.19.1/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.19.1/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.19.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/seh/redacted/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/pm/0n7z4ljx1c78_d3vb379cqgc0000gn/T/go-build1922992552=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Read the documentation for the os/exec package's Cmd.ProcessState field. Note that it promises that its value will be available "after a call to Wait or Run.

Write a program that calls on the (*Cmd).Run method that invokes a nominated command that does not exist (that is, the Cmd.Path field's value does not designate a readable, executable file), then attempt to call methods on the *os.ProcessState field value that I expect to be present in the Cmd's "ProcessState" field.

What did you expect to see?

The Cmd's "ProcessField" value would be a non-nil pointer to an os.ProcessState.

What did you see instead?

My program panics dereferencing a nil pointer. The Cmd.ProcessState field remains nil after (*Cmd).Run returns.

Diagnosis

(*Cmd).Run is a macro operation that does the following:

  • Call (*Cmd).Start.
  • If that succeeds, call (*Cmd).Wait.

It turns out that only after (*Cmd).Wait returns—assuming that (*Cmd).Start was called first, and that it hasn't been called already—is the Cmd.ProcessState field populated. If (*Cmd).Run's invocation of (*Cmd).Start fails, then the field will not be populated.

The documentation is simple, but misleading. It would be more accurate to say that the Cmd.ProcessState field will be populated after (*Cmd).Run starts the command.

I came upon this discrepancy while debugging a program that panicked in this situation. It took a while to figure out that the path to the command I was nominating in the Cmd.Path field was wrong, such that (*Cmd).Start—invoked via (*Cmd).Run—was failing. I figured that (*Cmd).Run had returned, even if it had returned an error, so I could count on the Cmd.ProcessState field's value being available for use.

Metadata

Metadata

Assignees

Labels

DocumentationIssues describing a change to documentation.FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions