From 575964d42c7b3001c09f2676d0ee9d520debb5eb Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 9 Nov 2022 09:42:04 -0800 Subject: [PATCH] cmd/go: improve handling of os.DevNull on Windows The "go test" and "go build" commands have special-case behavior when passed "-o /dev/null". These checks are case-sensitive and assume that os.DevNull is an absolute path. Windows filesystems are case-insensitive and os.DevNull is NUL, which is not an absolute path. CL 145220 changed filepath.IsAbs to report "NUL" as absolute to work around this issue; that change is being rolled back and a better fix here is to compare the value of -o against os.DevNull before attempting to merge it with a base path. Make that fix. On Windows, accept any capitilization of "NUL" as the null device. This change doesn't cover every possible name for the null device, such as "-o //./NUL", but this test is for efficiency rather than correctness. Accepting just the most common name is fine. For #56217. Change-Id: I60b59b671789fc456074d3c8bc755a74ea8d5765 Reviewed-on: https://go-review.googlesource.com/c/go/+/449117 TryBot-Result: Gopher Robot Run-TryBot: Damien Neil Reviewed-by: Bryan Mills --- src/cmd/go/internal/base/path.go | 15 +++++++++++++++ src/cmd/go/internal/test/test.go | 7 +++++-- src/cmd/go/internal/work/build.go | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go index 4d8715ef5fe..ebe4f153ed2 100644 --- a/src/cmd/go/internal/base/path.go +++ b/src/cmd/go/internal/base/path.go @@ -7,6 +7,7 @@ package base import ( "os" "path/filepath" + "runtime" "strings" "sync" ) @@ -54,3 +55,17 @@ func IsTestFile(file string) bool { // We don't cover tests, only the code they test. return strings.HasSuffix(file, "_test.go") } + +// IsNull reports whether the path is a common name for the null device. +// It returns true for /dev/null on Unix, or NUL (case-insensitive) on Windows. +func IsNull(path string) bool { + if path == os.DevNull { + return true + } + if runtime.GOOS == "windows" { + if strings.EqualFold(path, "NUL") { + return true + } + } + return false +} diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 6ec32dfa1e4..5a560098294 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -1010,13 +1010,16 @@ func builderTest(b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts, if testC || testNeedBinary() { // -c or profiling flag: create action to copy binary to ./test.out. target := filepath.Join(base.Cwd(), testBinary+cfg.ExeSuffix) + isNull := false if testO != "" { target = testO - if !filepath.IsAbs(target) { + if base.IsNull(target) { + isNull = true + } else if !filepath.IsAbs(target) { target = filepath.Join(base.Cwd(), target) } } - if target == os.DevNull { + if isNull { runAction = buildAction } else { pmain.Target = target diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 98babc0024e..848f07029f1 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -482,7 +482,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) { pkgs = omitTestOnly(pkgsFilter(pkgs)) // Special case -o /dev/null by not writing at all. - if cfg.BuildO == os.DevNull { + if base.IsNull(cfg.BuildO) { cfg.BuildO = "" }