]> Cypherpunks repositories - gostls13.git/commitdiff
os/exec: on Windows look for extensions in Run if not already done
authorqiulaidongfeng <2645477756@qq.com>
Wed, 5 Jun 2024 19:06:31 +0000 (19:06 +0000)
committerGopher Robot <gobot@golang.org>
Fri, 7 Jun 2024 20:13:53 +0000 (20:13 +0000)
CL 512155 fixed #36768, but introduced #62596.
CL 527820 fixed #62596, but meant that the code failed to look up
file extensions on Windows for a relative path.
This CL fixes that problem by recording whether it has already
looked up file extensions.
This does mean that if Path is set manually then we do not update
it with file extensions, as doing that would be racy.

Fixes #66586

Change-Id: I9a0305d1e466c5e07bfbe442566ea12f5255a96e
GitHub-Last-Rev: dc3169f2350f61acac5ef7842b7514013abacbe1
GitHub-Pull-Request: golang/go#67035
Reviewed-on: https://go-review.googlesource.com/c/go/+/581695
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
src/os/exec/exec.go
src/os/exec/exec_test.go

index 35e4e7e792fdbc353b30a2e5128a0b616a6cc005..50ed3a8d165886c094bbd53e2ecc4ee9729146ad 100644 (file)
@@ -332,6 +332,10 @@ type Cmd struct {
        // See https://go.dev/blog/path-security
        // and https://go.dev/issue/43724 for more context.
        lookPathErr error
+
+       // cachedLookExtensions caches the result of calling lookExtensions.
+       // This is only used on Windows.
+       cachedLookExtensions string
 }
 
 // A ctxResult reports the result of watching the Context associated with a
@@ -430,16 +434,13 @@ func Command(name string, arg ...string) *Cmd {
                // We may need to add a filename extension from PATHEXT
                // or verify an extension that is already present.
                // Since the path is absolute, its extension should be unambiguous
-               // and independent of cmd.Dir, and we can go ahead and update cmd.Path to
-               // reflect it.
+               // and independent of cmd.Dir, and we can go ahead and cache the lookup now.
                //
                // Note that we cannot add an extension here for relative paths, because
                // cmd.Dir may be set after we return from this function and that may cause
                // the command to resolve to a different extension.
                lp, err := lookExtensions(name, "")
-               if lp != "" {
-                       cmd.Path = lp
-               }
+               cmd.cachedLookExtensions = lp
                if err != nil {
                        cmd.Err = err
                }
@@ -641,7 +642,10 @@ func (c *Cmd) Start() error {
                return c.Err
        }
        lp := c.Path
-       if runtime.GOOS == "windows" && !filepath.IsAbs(c.Path) {
+       if c.cachedLookExtensions != "" {
+               lp = c.cachedLookExtensions
+       }
+       if runtime.GOOS == "windows" && c.cachedLookExtensions == "" {
                // If c.Path is relative, we had to wait until now
                // to resolve it in case c.Dir was changed.
                // (If it is absolute, we already resolved its extension in Command
index c749de99db69e1f51ff9abe705eef50408cded95..dbe59fea119e70153ea28968dd934864dfd22010 100644 (file)
@@ -1835,3 +1835,32 @@ func TestPathRace(t *testing.T) {
        t.Logf("running in background: %v", cmd)
        <-done
 }
+
+func TestAbsPathExec(t *testing.T) {
+       testenv.MustHaveExec(t)
+       testenv.MustHaveGoBuild(t) // must have GOROOT/bin/gofmt, but close enough
+
+       // A simple exec of a full path should work.
+       // Go 1.22 broke this on Windows, requiring ".exe"; see #66586.
+       exe := filepath.Join(testenv.GOROOT(t), "bin/gofmt")
+       cmd := exec.Command(exe)
+       if cmd.Path != exe {
+               t.Errorf("exec.Command(%#q) set Path=%#q", exe, cmd.Path)
+       }
+       err := cmd.Run()
+       if err != nil {
+               t.Errorf("using exec.Command(%#q): %v", exe, err)
+       }
+
+       cmd = &exec.Cmd{Path: exe}
+       err = cmd.Run()
+       if err != nil {
+               t.Errorf("using exec.Cmd{Path: %#q}: %v", cmd.Path, err)
+       }
+
+       cmd = &exec.Cmd{Path: "gofmt", Dir: "/"}
+       err = cmd.Run()
+       if err == nil {
+               t.Errorf("using exec.Cmd{Path: %#q}: unexpected success", cmd.Path)
+       }
+}