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

(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.2​1.

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