This can be reproduced at tip, go1.23rc1, and go1.22.5 on Windows (but not other OSes). go1.22.4 and go1.21.12 are unaffected.
What did you do?
Create an *exec.Cmd
using exec.Command
, giving it an absolute path.
Modify its Path
field (and, optionally, Args[0]
) to point to another command.
Run it.
What did you see happen?
The modified value of Cmd.Path
is ignored. The command that's actually invoked is from the original Command
call.
What did you expect to see?
The command whose path is specified in Cmd.Path
is the one that's executed.
Here's a small reproducer. For brevity, it uses the go and gofmt binaries.
package main
import (
"fmt"
"os/exec"
)
func main() {
const exe1 = `C:\Program Files\Go\bin\go.exe`
const exe2 = `C:\Program Files\Go\bin\gofmt.exe`
cmd := exec.Command(exe1)
cmd.Path = exe2
cmd.Args = []string{cmd.Path}
if err := cmd.Run(); err == nil {
fmt.Println("OK: gofmt was executed")
} else {
fmt.Printf("fail: go was executed despite cmd.Path = %s\n", cmd.Path)
}
}
$ GOTOOLCHAIN=go1.22.4 go run ./p.go
OK: gofmt was executed
$ GOTOOLCHAIN=go1.21.12 go run ./p.go
OK: gofmt was executed
$ GOTOOLCHAIN=go1.23rc1 go run ./p.go
fail: go was executed despite cmd.Path = C:\Program Files\Go\bin\gofmt.exe
$ GOTOOLCHAIN=go1.22.5 go run ./p.go
fail: go was executed despite cmd.Path = C:\Program Files\Go\bin\gofmt.exe
CC @golang/windows, @ianlancetaylor.
Comment From: gabyhelp
Related Issues
- os/exec: calling Cmd.Start after setting Cmd.Path manually to absolute path without ".exe" no longer implicitly adds ".exe" in Go 1.22 #66586 (closed)
- os/exec: Cmd does not attempt to run ./prog.exe, when execution of ./prog requested #7377 (closed)
- os/exec: Cmd changes absolute path to relative when using go #28356 (closed)
- os/exec: unexpected ErrDot returned if there is an empty path in PATH #61493 (closed)
- os/exec: TestCommand fails on Windows when `NoDefaultCurrentDirectoryInExePath` is set in the environment #62594 (closed)
- os/exec: Cmd.Dir is not checked when looking for executable on Windows #21675 (closed)
- Command PATH security in Go > Securing os/exec by default
- os/exec: Command does a LookPath in the wrong place. #7228 (closed)
- os/exec: Cannot execute command with space in the name on Windows, when there are parameters #17149
- os/exec: Cmd.String races with Cmd.Start on Windows #62596 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: dmitshur
I sent CL 596875 with a proposed fix. Its approach is based on an earlier prototype (CL 575275) for #66586.
Comment From: gopherbot
Change https://go.dev/cl/596875 mentions this issue: os/exec: only use cachedLookExtensions if Cmd.Path is unmodified
Comment From: qiulaidongfeng
It seems that as long as we determine the cachedLookextensions and cmd.Path has a common no extension path prefix determines whether to use cachedLookExtension, which can solve the issue.
Comment From: qiulaidongfeng
For example:C:\go.exe and C:\gofmt, no extension path is C:\go and C:\gofmt ,it no equel, so don't use cachedLookExtension.
Comment From: qiulaidongfeng
If the no extension path is the same and the extension is different, my solution will fail. For example: if Cmd.Path is C:\go.exe change to C:\go.bat , these two paths are different executable files, and my solution will fail, but CL596875 will not. Sorry for the noise caused.
Comment From: dmitshur
@gopherbot Please backport to Go 1.22. Only Go 1.22 needs the fix, as this isn't an issue in Go 1.21.
This is a regression that can cause wrong binaries to be executed on Windows, with no workaround other than changing user code.
Comment From: gopherbot
Backport issue(s) opened: #68331 (for 1.22).
Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases.
Comment From: gopherbot
Change https://go.dev/cl/596976 mentions this issue: [release-branch.go1.22] os/exec: only use cachedLookExtensions if Cmd.Path is unmodified