go: cmd/go: go test -o NUL fails on Windows

go test command manages os.DevNull on Windows as relative path not as null device.

What version of Go are you using (go version)?

go version go1.11.1 windows/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Jupiter\AppData\Local\go-build
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\Jupiter\go
set GOPROXY=
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\Jupiter\AppData\Local\Temp\go-build946346806=/tmp/go-build -gno-record-gcc-switches

What did you do?

go test -c -work -o NUL

What did you expect to see?

WORK=C:\Users\Jupiter\AppData\Local\Temp\go-build814365262

What did you see instead?

WORK=C:\Users\Jupiter\AppData\Local\Temp\go-build814365262 go test /C/Users/Jupiter/Documents/echo.test: build output “C:\Users\Jupiter\Documents\echo\NUL” already exists and is not an object file


Hi,

Since the go1.11, still true with the latest version go1.11.1, the os.DevNull value for Windows is not well managed by the go test command (see file flag). NUL is managed as relative path, not as null device. I suggest to add something like that in the file src/cmd/go/internal/test/testflag.go to deal with the -o flag:

// Special case -o /dev/null by not writing at all.
testO = value
if testO == os.DevNull {
	testO = ""
}
testNeedBinary = true

Sample code to reproduce :

// file: echo/echo.go
package echo

func Echo(s string) string {
	return s
}
// file: echo/echo_test.go
package echo

import "testing"

const testdata = "hi"

func TestClientMustProcess(t *testing.T) {
	if s := Echo(testdata); s != testdata {
		t.Fatalf("unexpected result: got=%q exp=%q", s, testdata)
	}
}

Then, inside the echo package directory, run the go test command with file flag: - o.

Hope it helps.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 17 (13 by maintainers)

Most upvoted comments

Finally I had time to understand why https://github.com/golang/go/commit/e83601b4356f92f2f4d05f302d5654754ff05a6d introduces this issue.

The issue happens because path/filepath.IsAbs(“NUL”) returns false. See this code

https://github.com/golang/go/blob/b4150f76144808bf0015fe23be0e2ade32a14599/src/cmd/go/internal/test/test.go#L886-L888

target is set to “NUL” on line 886, and it becomes “C:\Users\Jupiter\Documents\echo\NUL” on line 887.

The difference of what code does before and after https://github.com/golang/go/commit/e83601b4356f92f2f4d05f302d5654754ff05a6d can be seen here (dst is set to “C:\Users\Jupiter\Documents\echo\NUL”)

https://github.com/golang/go/blob/b4150f76144808bf0015fe23be0e2ade32a14599/src/cmd/go/internal/work/exec.go#L1560-L1567

Before https://github.com/golang/go/commit/e83601b4356f92f2f4d05f302d5654754ff05a6d os.Stat on line 1560 fails, so none of 1561-L1567 lines run.

And after https://github.com/golang/go/commit/e83601b4356f92f2f4d05f302d5654754ff05a6d os.Stat succeeds. I think the fact that os.Stat(C:\Users\Jupiter\Documents\echo\NUL) succeeds is fine - any file with the name of NUL is treated as NUL on Windows (I tried this https://play.golang.org/p/c1-Zh0p3D2W program, and it succeeds on my computer). But then the fi.Mode().IsRegular() on line 1564 returns true, and that is wrong. If you look at current os.Stat implementation, we determine NUL device by comparing os.Stat parameter with “NUL” string, so that obviously fails for C:\Users\Jupiter\Documents\echo\NUL.

Anyways, we could change os.Stat(C:\Users\Jupiter\Documents\echo\NUL) to return Mode().IsRegular() false. But the main problem here is that path/filepath.IsAbs(“NUL”) returns false.

So, should we make path/filepath.IsAbs(“NUL”) return false? ( and others, like CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9 - search https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file for NUL). Is that the right thing to do? Should we similarly handle other functions in path/filepath ?

Alternatively, we could special case NUL in cmd/go, like Russ did in https://github.com/golang/go/commit/a3faa80033ae2ffa3ee56439759f0ea0200a3a3e - Russ adjusted go build code, we need to adjust do test code. Interestingly, we have cmd/go.TestGoBuildDashODevNull, but cmd/go.TestGoTestDashODevNull is missing.

Also https://github.com/golang/go/commit/a3faa80033ae2ffa3ee56439759f0ea0200a3a3e determines os.DevNull by comparing cmd/go parameter with os.DevNull string. That will not work on Windows because user can pass both NUL and nul. So we would need to deal with that too. Luckily https://github.com/golang/go/commit/a3faa80033ae2ffa3ee56439759f0ea0200a3a3e is a NOP on Windows, so it is not important there.

Sorry for long comment.

I need decision here (I can create a proposal, if needed).

@ianlancetaylor @bradfitz @mattn and everyone else who has anything to add here

Thank you.

Alex