Skip to content

Commit dfe4dbf

Browse files
qiulaidongfenggopherbot
authored andcommitted
[release-branch.go1.22] os/exec: on Windows look for extensions in Run if not already done
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. For #66586 Fixes #66598 Change-Id: I9a0305d1e466c5e07bfbe442566ea12f5255a96e GitHub-Last-Rev: dc3169f GitHub-Pull-Request: #67035 Reviewed-on: https://go-review.googlesource.com/c/go/+/581695 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> (cherry picked from commit 5532427) Reviewed-on: https://go-review.googlesource.com/c/go/+/594495 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]>
1 parent 3560cf0 commit dfe4dbf

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/os/exec/exec.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ type Cmd struct {
332332
// See https://go.dev/blog/path-security
333333
// and https://go.dev/issue/43724 for more context.
334334
lookPathErr error
335+
336+
// cachedLookExtensions caches the result of calling lookExtensions.
337+
// This is only used on Windows.
338+
cachedLookExtensions string
335339
}
336340

337341
// A ctxResult reports the result of watching the Context associated with a
@@ -430,16 +434,13 @@ func Command(name string, arg ...string) *Cmd {
430434
// We may need to add a filename extension from PATHEXT
431435
// or verify an extension that is already present.
432436
// Since the path is absolute, its extension should be unambiguous
433-
// and independent of cmd.Dir, and we can go ahead and update cmd.Path to
434-
// reflect it.
437+
// and independent of cmd.Dir, and we can go ahead and cache the lookup now.
435438
//
436439
// Note that we cannot add an extension here for relative paths, because
437440
// cmd.Dir may be set after we return from this function and that may cause
438441
// the command to resolve to a different extension.
439442
lp, err := lookExtensions(name, "")
440-
if lp != "" {
441-
cmd.Path = lp
442-
}
443+
cmd.cachedLookExtensions = lp
443444
if err != nil {
444445
cmd.Err = err
445446
}
@@ -641,7 +642,10 @@ func (c *Cmd) Start() error {
641642
return c.Err
642643
}
643644
lp := c.Path
644-
if runtime.GOOS == "windows" && !filepath.IsAbs(c.Path) {
645+
if c.cachedLookExtensions != "" {
646+
lp = c.cachedLookExtensions
647+
}
648+
if runtime.GOOS == "windows" && c.cachedLookExtensions == "" {
645649
// If c.Path is relative, we had to wait until now
646650
// to resolve it in case c.Dir was changed.
647651
// (If it is absolute, we already resolved its extension in Command

src/os/exec/exec_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -1835,3 +1835,32 @@ func TestPathRace(t *testing.T) {
18351835
t.Logf("running in background: %v", cmd)
18361836
<-done
18371837
}
1838+
1839+
func TestAbsPathExec(t *testing.T) {
1840+
testenv.MustHaveExec(t)
1841+
testenv.MustHaveGoBuild(t) // must have GOROOT/bin/gofmt, but close enough
1842+
1843+
// A simple exec of a full path should work.
1844+
// Go 1.22 broke this on Windows, requiring ".exe"; see #66586.
1845+
exe := filepath.Join(testenv.GOROOT(t), "bin/gofmt")
1846+
cmd := exec.Command(exe)
1847+
if cmd.Path != exe {
1848+
t.Errorf("exec.Command(%#q) set Path=%#q", exe, cmd.Path)
1849+
}
1850+
err := cmd.Run()
1851+
if err != nil {
1852+
t.Errorf("using exec.Command(%#q): %v", exe, err)
1853+
}
1854+
1855+
cmd = &exec.Cmd{Path: exe}
1856+
err = cmd.Run()
1857+
if err != nil {
1858+
t.Errorf("using exec.Cmd{Path: %#q}: %v", cmd.Path, err)
1859+
}
1860+
1861+
cmd = &exec.Cmd{Path: "gofmt", Dir: "/"}
1862+
err = cmd.Run()
1863+
if err == nil {
1864+
t.Errorf("using exec.Cmd{Path: %#q}: unexpected success", cmd.Path)
1865+
}
1866+
}

0 commit comments

Comments
 (0)