-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
What version of Go are you using (go version
)?
$ go version go1.20.2
Does this issue reproduce with the latest release?
no tested yet
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go envGO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="~/Library/Caches/go-build"
GOENV="~/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="~/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="~/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="~/.g/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="~/.g/go/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="~/Library/Application Support/JetBrains/GoLand2023.1/scratches/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/bz/g8kmk1fn0xj0rnprc0v0h33r0000gn/T/go-build1655805848=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
As an apology, although my build env is Mac M1
, I cross-compiled the application into the amd64 windows
.
So this is a description of the Windows system.
I missed to set my PATH with a empty path, like path1;;path2;
So when I wanted to use exec.Command
to open the cmd.exe
(my working directory is C:/Windows/System32
, just the same as cmd.exe
lies), I got aErrDot
.
In this situation, I got 2 ways to find the cmd.exe
in PATH. The one is to find in the absolute path C:/Windows/System32
, and the other one is the empty path which I entered by mistake. And the empty one comes first.
Lines 103 to 139 in 8abc6e2
if _, found := syscall.Getenv("NoDefaultCurrentDirectoryInExePath"); !found { | |
if f, err := findExecutable(filepath.Join(".", file), exts); err == nil { | |
if execerrdot.Value() == "0" { | |
execerrdot.IncNonDefault() | |
return f, nil | |
} | |
dotf, dotErr = f, &Error{file, ErrDot} | |
} | |
} | |
path := os.Getenv("path") | |
for _, dir := range filepath.SplitList(path) { | |
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil { | |
if dotErr != nil { | |
// https://go.dev/issue/53536: if we resolved a relative path implicitly, | |
// and it is the same executable that would be resolved from the explicit %PATH%, | |
// prefer the explicit name for the executable (and, likely, no error) instead | |
// of the equivalent implicit name with ErrDot. | |
// | |
// Otherwise, return the ErrDot for the implicit path as soon as we find | |
// out that the explicit one doesn't match. | |
dotfi, dotfiErr := os.Lstat(dotf) | |
fi, fiErr := os.Lstat(f) | |
if dotfiErr != nil || fiErr != nil || !os.SameFile(dotfi, fi) { | |
return dotf, dotErr | |
} | |
} | |
if !filepath.IsAbs(f) { | |
if execerrdot.Value() != "0" { | |
return f, &Error{file, ErrDot} | |
} | |
execerrdot.IncNonDefault() | |
} | |
return f, nil | |
} | |
} |
In line 114, it enters the empty path which is considered as the .
path, and finds cmd.exe
in this path.
Without a doubt, it is treated as a RELATIVE PATH
and returned with an ErrDot.
I know the relative path is forbidden now.
And I think this is similar to the problem mentioned in the #53536, but not exactly the same.
What did you expect to see?
I have to admit that this is my fault to set an empty path by mistake.
But I still wonder whether the logic in this code should be optimized or not.
Provided with my two opinions as below:
-
In the PATH list, skip the empty path or anything like the relative path which will function as the
.
path eventually. After all, there is no need to deal with the.
path in this code, because it has been dealt with before. -
We can sort the list before range it. Make the absolute paths come before the relative paths.