libgo: update to Go1.15.2 release
authorIan Lance Taylor <iant@golang.org>
Wed, 23 Sep 2020 03:30:08 +0000 (20:30 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 24 Sep 2020 00:32:49 +0000 (17:32 -0700)
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/256618

34 files changed:
gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/VERSION
libgo/go/cmd/go/internal/test/test.go
libgo/go/cmd/go/internal/test/testflag.go
libgo/go/cmd/go/testdata/script/test_flags.txt [new file with mode: 0644]
libgo/go/cmd/internal/test2json/test2json.go
libgo/go/cmd/internal/test2json/testdata/benchshort.json
libgo/go/cmd/internal/test2json/testdata/empty.json [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/empty.test [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/issue29755.json [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/issue29755.test [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/panic.json [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/panic.test [new file with mode: 0644]
libgo/go/cmd/internal/test2json/testdata/smiley.json
libgo/go/cmd/internal/test2json/testdata/smiley.test
libgo/go/cmd/internal/test2json/testdata/vet.json
libgo/go/cmd/internal/test2json/testdata/vet.test
libgo/go/cmd/test2json/main.go
libgo/go/internal/poll/copy_file_range_linux.go
libgo/go/net/http/cgi/child.go
libgo/go/net/http/cgi/child_test.go
libgo/go/net/http/cgi/integration_test.go
libgo/go/net/http/fcgi/child.go
libgo/go/net/http/fcgi/fcgi_test.go
libgo/go/net/mail/message.go
libgo/go/net/mail/message_test.go
libgo/go/runtime/checkptr_test.go
libgo/go/runtime/lockrank_off.go
libgo/go/runtime/testdata/testprog/checkptr.go
libgo/go/sync/map.go
libgo/go/sync/map_test.go
libgo/go/testing/testing.go
libgo/merge.sh

index 5d26b7e2da1b76ea9768288b4eb996bc03fbe1a7..f51dac553653144ccc07543643dded4c4e5858e0 100644 (file)
@@ -1,4 +1,4 @@
-cfee06e20a172753552b1515dd3a4fde5d5cad7b
+6a7648c97c3e0cdbecbec7e760b30246521a6d90
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index a84f1e38f9d4adf5acc4dbdeeacc50426c444cd9..cfbf488398e145fd3e627d9852126e09815a93d9 100644 (file)
@@ -1,4 +1,4 @@
-c4f8cb43caf0bcd0c730d7d04a3fce129393cecc
+9706f510a5e2754595d716bd64be8375997311fb
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index 2d962d8cd2716330bf58d3a04b64481dfd9d28f1..c19def3de444fa5012ca599d7e8d16a14743ca8f 100644 (file)
@@ -1 +1 @@
-go1.15rc2
+go1.15.2
index 873a76aa38037e0d6cc5c00acfc12ddca1d0e2ff..77bfc11fe9a45dd64fd581216975debe8ca248a2 100644 (file)
@@ -1079,9 +1079,13 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error {
        }
 
        var stdout io.Writer = os.Stdout
+       var err error
        if testJSON {
                json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp)
-               defer json.Close()
+               defer func() {
+                       json.Exited(err)
+                       json.Close()
+               }()
                stdout = json
        }
 
@@ -1185,7 +1189,7 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error {
        }
 
        t0 := time.Now()
-       err := cmd.Start()
+       err = cmd.Start()
 
        // This is a last-ditch deadline to detect and
        // stop wedged test binaries, to keep the builders
index 1ff34f7445cd184ba2d5b153ecf21dd957a20b9e..4f0a8924f12c0bde08cf9b37a82717b6b9b6dda5 100644 (file)
@@ -214,9 +214,13 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 
        explicitArgs := make([]string, 0, len(args))
        inPkgList := false
+       afterFlagWithoutValue := false
        for len(args) > 0 {
                f, remainingArgs, err := cmdflag.ParseOne(&CmdTest.Flag, args)
 
+               wasAfterFlagWithoutValue := afterFlagWithoutValue
+               afterFlagWithoutValue = false // provisionally
+
                if errors.Is(err, flag.ErrHelp) {
                        exitWithUsage()
                }
@@ -233,10 +237,24 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) {
                        if !inPkgList && packageNames != nil {
                                // We already saw the package list previously, and this argument is not
-                               // a flag, so it — and everything after it — must be a literal argument
-                               // to the test binary.
-                               explicitArgs = append(explicitArgs, args...)
-                               break
+                               // a flag, so it — and everything after it — must be either a value for
+                               // a preceding flag or a literal argument to the test binary.
+                               if wasAfterFlagWithoutValue {
+                                       // This argument could syntactically be a flag value, so
+                                       // optimistically assume that it is and keep looking for go command
+                                       // flags after it.
+                                       //
+                                       // (If we're wrong, we'll at least be consistent with historical
+                                       // behavior; see https://golang.org/issue/40763.)
+                                       explicitArgs = append(explicitArgs, nf.RawArg)
+                                       args = remainingArgs
+                                       continue
+                               } else {
+                                       // This argument syntactically cannot be a flag value, so it must be a
+                                       // positional argument, and so must everything after it.
+                                       explicitArgs = append(explicitArgs, args...)
+                                       break
+                               }
                        }
 
                        inPkgList = true
@@ -272,6 +290,9 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 
                        explicitArgs = append(explicitArgs, nd.RawArg)
                        args = remainingArgs
+                       if !nd.HasValue {
+                               afterFlagWithoutValue = true
+                       }
                        continue
                }
 
diff --git a/libgo/go/cmd/go/testdata/script/test_flags.txt b/libgo/go/cmd/go/testdata/script/test_flags.txt
new file mode 100644 (file)
index 0000000..63385e6
--- /dev/null
@@ -0,0 +1,132 @@
+env GO111MODULE=on
+
+[short] skip
+
+# Arguments after the flag terminator should be ignored.
+# If we pass '-- -test.v', we should not get verbose output
+# *and* output from the test should not be echoed.
+go test ./x -- -test.v
+stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z'
+! stderr .
+
+# For backward-compatibility with previous releases of the 'go' command,
+# arguments that appear after unrecognized flags should not be treated
+# as packages, even if they are unambiguously not arguments to flags.
+# Even though ./x looks like a package path, the real package should be
+# the implicit '.'.
+! go test --answer=42 ./x
+stderr '^no Go files in .+$'
+! stderr '/x'
+
+# However, *flags* that appear after unrecognized flags should still be
+# interpreted as flags, under the (possibly-erroneous) assumption that
+# unrecognized flags are non-boolean.
+
+go test -v -x ./x -timeout 24h -boolflag=true foo -timeout 25h
+stdout 'args: foo -timeout 25h'
+stdout 'timeout: 24h0m0s$'  # -timeout is unambiguously not a flag, so the real flag wins.
+
+go test -v -x ./x -timeout 24h -boolflag foo -timeout 25h
+stdout 'args: foo -test\.timeout=25h0m0s'  # For legacy reasons, '-timeout ' is erroneously rewritten to -test.timeout; see https://golang.org/issue/40763.
+stdout 'timeout: 24h0m0s$'  # Actual flag wins.
+
+go test -v -x ./x -timeout 24h -stringflag foo -timeout 25h
+stdout 'args: $'
+stdout 'timeout: 25h0m0s$'  # Later flag wins.
+
+# An explicit '-outputdir=' argument should set test.outputdir
+# to the 'go' command's working directory, not zero it out
+# for the test binary.
+go test -x -coverprofile=cover.out '-outputdir=' ./x
+stderr '-test.outputdir=[^ ]'
+exists ./cover.out
+! exists ./x/cover.out
+
+# Test flags from GOFLAGS should be forwarded to the test binary,
+# with the 'test.' prefix in the GOFLAGS entry...
+env GOFLAGS='-test.timeout=24h0m0s -count=1'
+go test -v -x ./x
+stdout 'timeout: 24h0m0s$'
+stderr '-test.count=1'
+
+# ...or without.
+env GOFLAGS='-timeout=24h0m0s -count=1'
+go test -v -x ./x
+stdout 'timeout: 24h0m0s$'
+stderr '-test.count=1'
+
+# Arguments from the command line should override GOFLAGS...
+go test -v -x -timeout=25h0m0s ./x
+stdout 'timeout: 25h0m0s$'
+stderr '-test.count=1'
+
+# ...even if they use a different flag name.
+go test -v -x -test.timeout=26h0m0s ./x
+stdout 'timeout: 26h0m0s$'
+stderr '-test\.timeout=26h0m0s'
+! stderr 'timeout=24h0m0s'
+stderr '-test.count=1'
+
+# Invalid flags should be reported exactly once.
+! go test -covermode=walrus ./x
+stderr -count=1 'invalid value "walrus" for flag -covermode: valid modes are .*$'
+stderr '^usage: go test .*$'
+stderr '^Run ''go help test'' and ''go help testflag'' for details.$'
+
+# Passing -help to the test binary should show flag help.
+go test ./x -args -help
+stdout 'usage_message'
+
+# -covermode, -coverpkg, and -coverprofile should imply -cover
+go test -covermode=set ./x
+stdout '\s+coverage:\s+'
+
+go test -coverpkg=encoding/binary ./x
+stdout '\s+coverage:\s+'
+
+go test -coverprofile=cover.out ./x
+stdout '\s+coverage:\s+'
+exists ./cover.out
+rm ./cover.out
+
+# -*profile and -trace flags should force output to the current working directory
+# or -outputdir, not the directory containing the test.
+
+go test -memprofile=mem.out ./x
+exists ./mem.out
+rm ./mem.out
+
+go test -trace=trace.out ./x
+exists ./trace.out
+rm ./trace.out
+
+# Relative paths with -outputdir should be relative to the go command's working
+# directory, not the directory containing the test.
+mkdir profiles
+go test -memprofile=mem.out -outputdir=./profiles ./x
+exists ./profiles/mem.out
+rm profiles
+
+-- go.mod --
+module example.com
+go 1.14
+-- x/x_test.go --
+package x
+
+import (
+       "flag"
+       "strings"
+       "testing"
+)
+
+var _ = flag.String("usage_message", "", "dummy flag to check usage message")
+var boolflag = flag.Bool("boolflag", false, "ignored boolean flag")
+var stringflag = flag.String("stringflag", "", "ignored string flag")
+
+func TestLogTimeout(t *testing.T) {
+       t.Logf("timeout: %v", flag.Lookup("test.timeout").Value)
+}
+
+func TestLogArgs(t *testing.T) {
+       t.Logf("args: %s", strings.Join(flag.Args(), " "))
+}
index f8052136be625025bd47f8e2d771e837c44794e6..4eb6dd4838b507057bca801aa4d3edbbc28026fe 100644 (file)
@@ -45,10 +45,10 @@ type textBytes []byte
 
 func (b textBytes) MarshalText() ([]byte, error) { return b, nil }
 
-// A converter holds the state of a test-to-JSON conversion.
+// A Converter holds the state of a test-to-JSON conversion.
 // It implements io.WriteCloser; the caller writes test output in,
 // and the converter writes JSON output to w.
-type converter struct {
+type Converter struct {
        w        io.Writer  // JSON output stream
        pkg      string     // package to name in events
        mode     Mode       // mode bits
@@ -100,9 +100,9 @@ var (
 //
 // The pkg string, if present, specifies the import path to
 // report in the JSON stream.
-func NewConverter(w io.Writer, pkg string, mode Mode) io.WriteCloser {
-       c := new(converter)
-       *c = converter{
+func NewConverter(w io.Writer, pkg string, mode Mode) *Converter {
+       c := new(Converter)
+       *c = Converter{
                w:     w,
                pkg:   pkg,
                mode:  mode,
@@ -122,15 +122,31 @@ func NewConverter(w io.Writer, pkg string, mode Mode) io.WriteCloser {
 }
 
 // Write writes the test input to the converter.
-func (c *converter) Write(b []byte) (int, error) {
+func (c *Converter) Write(b []byte) (int, error) {
        c.input.write(b)
        return len(b), nil
 }
 
+// Exited marks the test process as having exited with the given error.
+func (c *Converter) Exited(err error) {
+       if err == nil {
+               c.result = "pass"
+       } else {
+               c.result = "fail"
+       }
+}
+
 var (
+       // printed by test on successful run.
        bigPass = []byte("PASS\n")
+
+       // printed by test after a normal test failure.
        bigFail = []byte("FAIL\n")
 
+       // printed by 'go test' along with an error if the test binary terminates
+       // with an error.
+       bigFailErrorPrefix = []byte("FAIL\t")
+
        updates = [][]byte{
                []byte("=== RUN   "),
                []byte("=== PAUSE "),
@@ -153,9 +169,9 @@ var (
 // handleInputLine handles a single whole test output line.
 // It must write the line to c.output but may choose to do so
 // before or after emitting other events.
-func (c *converter) handleInputLine(line []byte) {
+func (c *Converter) handleInputLine(line []byte) {
        // Final PASS or FAIL.
-       if bytes.Equal(line, bigPass) || bytes.Equal(line, bigFail) {
+       if bytes.Equal(line, bigPass) || bytes.Equal(line, bigFail) || bytes.HasPrefix(line, bigFailErrorPrefix) {
                c.flushReport(0)
                c.output.write(line)
                if bytes.Equal(line, bigPass) {
@@ -204,8 +220,18 @@ func (c *converter) handleInputLine(line []byte) {
                }
        }
 
+       // Not a special test output line.
        if !ok {
-               // Not a special test output line.
+               // Lookup the name of the test which produced the output using the
+               // indentation of the output as an index into the stack of the current
+               // subtests.
+               // If the indentation is greater than the number of current subtests
+               // then the output must have included extra indentation. We can't
+               // determine which subtest produced this output, so we default to the
+               // old behaviour of assuming the most recently run subtest produced it.
+               if indent > 0 && indent <= len(c.report) {
+                       c.testName = c.report[indent-1].Test
+               }
                c.output.write(origLine)
                return
        }
@@ -269,7 +295,7 @@ func (c *converter) handleInputLine(line []byte) {
 }
 
 // flushReport flushes all pending PASS/FAIL reports at levels >= depth.
-func (c *converter) flushReport(depth int) {
+func (c *Converter) flushReport(depth int) {
        c.testName = ""
        for len(c.report) > depth {
                e := c.report[len(c.report)-1]
@@ -281,23 +307,22 @@ func (c *converter) flushReport(depth int) {
 // Close marks the end of the go test output.
 // It flushes any pending input and then output (only partial lines at this point)
 // and then emits the final overall package-level pass/fail event.
-func (c *converter) Close() error {
+func (c *Converter) Close() error {
        c.input.flush()
        c.output.flush()
-       e := &event{Action: "fail"}
        if c.result != "" {
-               e.Action = c.result
-       }
-       if c.mode&Timestamp != 0 {
-               dt := time.Since(c.start).Round(1 * time.Millisecond).Seconds()
-               e.Elapsed = &dt
+               e := &event{Action: c.result}
+               if c.mode&Timestamp != 0 {
+                       dt := time.Since(c.start).Round(1 * time.Millisecond).Seconds()
+                       e.Elapsed = &dt
+               }
+               c.writeEvent(e)
        }
-       c.writeEvent(e)
        return nil
 }
 
 // writeOutputEvent writes a single output event with the given bytes.
-func (c *converter) writeOutputEvent(out []byte) {
+func (c *Converter) writeOutputEvent(out []byte) {
        c.writeEvent(&event{
                Action: "output",
                Output: (*textBytes)(&out),
@@ -306,7 +331,7 @@ func (c *converter) writeOutputEvent(out []byte) {
 
 // writeEvent writes a single event.
 // It adds the package, time (if requested), and test name (if needed).
-func (c *converter) writeEvent(e *event) {
+func (c *Converter) writeEvent(e *event) {
        e.Package = c.pkg
        if c.mode&Timestamp != 0 {
                t := time.Now()
index 8c61d95d8da0235d23a2a2fd4576baf087006e96..34b03b9362fa42a7502a33935744a10edb1525a5 100644 (file)
@@ -4,4 +4,3 @@
 {"Action":"output","Output":"# but to avoid questions of timing, we just use a file with no \\n at all.\n"}
 {"Action":"output","Output":"BenchmarkFoo   \t"}
 {"Action":"output","Output":"10000 early EOF"}
-{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/empty.json b/libgo/go/cmd/internal/test2json/testdata/empty.json
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/libgo/go/cmd/internal/test2json/testdata/empty.test b/libgo/go/cmd/internal/test2json/testdata/empty.test
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue29755.json b/libgo/go/cmd/internal/test2json/testdata/issue29755.json
new file mode 100644 (file)
index 0000000..2e8ba48
--- /dev/null
@@ -0,0 +1,38 @@
+{"Action":"run","Test":"TestOutputWithSubtest"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"=== RUN   TestOutputWithSubtest\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"=== RUN   TestOutputWithSubtest/sub_test\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test/sub2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"=== RUN   TestOutputWithSubtest/sub_test/sub2\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"=== RUN   TestOutputWithSubtest/sub_test2\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test2/sub2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"=== RUN   TestOutputWithSubtest/sub_test2/sub2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"--- FAIL: TestOutputWithSubtest (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:6: output before sub tests\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:10: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:15: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"    --- PASS: TestOutputWithSubtest/sub_test (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"        foo_test.go:9: output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"        foo_test.go:11: more output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"        foo_test.go:16: more output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"        --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"            foo_test.go:14: output from sub2 test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:22: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:27: output from root test\n"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test/sub2"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"    --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"        foo_test.go:21: output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"        foo_test.go:23: more output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"        foo_test.go:28: more output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"        --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"            foo_test.go:26: output from sub2 test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"    foo_test.go:32: output after sub test\n"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2/sub2"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2"}
+{"Action":"fail","Test":"TestOutputWithSubtest"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\tgotest.tools/gotestsum/foo\t0.001s\n"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue29755.test b/libgo/go/cmd/internal/test2json/testdata/issue29755.test
new file mode 100644 (file)
index 0000000..b0c596c
--- /dev/null
@@ -0,0 +1,27 @@
+=== RUN   TestOutputWithSubtest
+=== RUN   TestOutputWithSubtest/sub_test
+=== RUN   TestOutputWithSubtest/sub_test/sub2
+=== RUN   TestOutputWithSubtest/sub_test2
+=== RUN   TestOutputWithSubtest/sub_test2/sub2
+--- FAIL: TestOutputWithSubtest (0.00s)
+    foo_test.go:6: output before sub tests
+    foo_test.go:10: output from root test
+    foo_test.go:15: output from root test
+    --- PASS: TestOutputWithSubtest/sub_test (0.00s)
+        foo_test.go:9: output from sub test
+        foo_test.go:11: more output from sub test
+        foo_test.go:16: more output from sub test
+        --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)
+            foo_test.go:14: output from sub2 test
+    foo_test.go:22: output from root test
+    foo_test.go:27: output from root test
+    --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)
+        foo_test.go:21: output from sub test2
+        foo_test.go:23: more output from sub test2
+        foo_test.go:28: more output from sub test2
+        --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)
+            foo_test.go:26: output from sub2 test
+    foo_test.go:32: output after sub test
+FAIL
+FAIL   gotest.tools/gotestsum/foo      0.001s
+FAIL
diff --git a/libgo/go/cmd/internal/test2json/testdata/panic.json b/libgo/go/cmd/internal/test2json/testdata/panic.json
new file mode 100644 (file)
index 0000000..f773814
--- /dev/null
@@ -0,0 +1,19 @@
+{"Action":"output","Test":"TestPanic","Output":"--- FAIL: TestPanic (0.00s)\n"}
+{"Action":"output","Test":"TestPanic","Output":"panic: oops [recovered]\n"}
+{"Action":"output","Test":"TestPanic","Output":"\tpanic: oops\n"}
+{"Action":"output","Test":"TestPanic","Output":"\n"}
+{"Action":"output","Test":"TestPanic","Output":"goroutine 7 [running]:\n"}
+{"Action":"output","Test":"TestPanic","Output":"testing.tRunner.func1(0xc000092100)\n"}
+{"Action":"output","Test":"TestPanic","Output":"\t/go/src/testing/testing.go:874 +0x3a3\n"}
+{"Action":"output","Test":"TestPanic","Output":"panic(0x1110ea0, 0x116aea0)\n"}
+{"Action":"output","Test":"TestPanic","Output":"\t/go/src/runtime/panic.go:679 +0x1b2\n"}
+{"Action":"output","Test":"TestPanic","Output":"command-line-arguments.TestPanic(0xc000092100)\n"}
+{"Action":"output","Test":"TestPanic","Output":"\ta_test.go:6 +0x39\n"}
+{"Action":"output","Test":"TestPanic","Output":"testing.tRunner(0xc000092100, 0x114f500)\n"}
+{"Action":"output","Test":"TestPanic","Output":"\tgo/src/testing/testing.go:909 +0xc9\n"}
+{"Action":"output","Test":"TestPanic","Output":"created by testing.(*T).Run\n"}
+{"Action":"output","Test":"TestPanic","Output":"\tgo/src/testing/testing.go:960 +0x350\n"}
+{"Action":"fail","Test":"TestPanic"}
+{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.042s\n"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/panic.test b/libgo/go/cmd/internal/test2json/testdata/panic.test
new file mode 100644 (file)
index 0000000..517ebaf
--- /dev/null
@@ -0,0 +1,17 @@
+--- FAIL: TestPanic (0.00s)
+panic: oops [recovered]
+       panic: oops
+
+goroutine 7 [running]:
+testing.tRunner.func1(0xc000092100)
+       /go/src/testing/testing.go:874 +0x3a3
+panic(0x1110ea0, 0x116aea0)
+       /go/src/runtime/panic.go:679 +0x1b2
+command-line-arguments.TestPanic(0xc000092100)
+       a_test.go:6 +0x39
+testing.tRunner(0xc000092100, 0x114f500)
+       go/src/testing/testing.go:909 +0xc9
+created by testing.(*T).Run
+       go/src/testing/testing.go:960 +0x350
+FAIL   command-line-arguments  0.042s
+FAIL
index afa990d7c03f12bc73032214a1b77f463dfaad86..f49180d52074ae5331482977d0d1a576527c5dfe 100644 (file)
 {"Action":"output","Test":"Test☺☹/2","Output":"=== CONT  Test☺☹/2\n"}
 {"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
 {"Action":"output","Test":"TestTags/x_testtag_y","Output":"    --- PASS: TestTags/x_testtag_y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"    \tvet_test.go:187: -tags=x testtag y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"        vet_test.go:187: -tags=x testtag y\n"}
 {"Action":"pass","Test":"TestTags/x_testtag_y"}
 {"Action":"output","Test":"TestTags/x,testtag,y","Output":"    --- PASS: TestTags/x,testtag,y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"    \tvet_test.go:187: -tags=x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"        vet_test.go:187: -tags=x,testtag,y\n"}
 {"Action":"pass","Test":"TestTags/x,testtag,y"}
 {"Action":"output","Test":"TestTags/testtag","Output":"    --- PASS: TestTags/testtag (0.04s)\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":"    \tvet_test.go:187: -tags=testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"        vet_test.go:187: -tags=testtag\n"}
 {"Action":"pass","Test":"TestTags/testtag"}
 {"Action":"pass","Test":"TestTags"}
 {"Action":"cont","Test":"Test☺☹/1"}
 {"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== CONT  Test☺☹Dirs/cgo\n"}
 {"Action":"output","Test":"Test☺☹","Output":"--- PASS: Test☺☹ (0.39s)\n"}
 {"Action":"output","Test":"Test☺☹/5","Output":"    --- PASS: Test☺☹/5 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/5","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/5","Output":"        vet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/5"}
 {"Action":"output","Test":"Test☺☹/3","Output":"    --- PASS: Test☺☹/3 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/3","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/3","Output":"        vet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/3"}
 {"Action":"output","Test":"Test☺☹/6","Output":"    --- PASS: Test☺☹/6 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/6","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/6","Output":"        vet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/6"}
 {"Action":"output","Test":"Test☺☹/2","Output":"    --- PASS: Test☺☹/2 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/2","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/2","Output":"        vet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/2"}
 {"Action":"output","Test":"Test☺☹/0","Output":"    --- PASS: Test☺☹/0 (0.13s)\n"}
-{"Action":"output","Test":"Test☺☹/0","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/0","Output":"        vet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/0"}
 {"Action":"output","Test":"Test☺☹/4","Output":"    --- PASS: Test☺☹/4 (0.16s)\n"}
-{"Action":"output","Test":"Test☺☹/4","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/4","Output":"        vet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/4"}
 {"Action":"output","Test":"Test☺☹/1","Output":"    --- PASS: Test☺☹/1 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/1","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/1","Output":"        vet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/1"}
 {"Action":"output","Test":"Test☺☹/7","Output":"    --- PASS: Test☺☹/7 (0.19s)\n"}
-{"Action":"output","Test":"Test☺☹/7","Output":"    \tvet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/7","Output":"        vet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
 {"Action":"pass","Test":"Test☺☹/7"}
 {"Action":"pass","Test":"Test☺☹"}
 {"Action":"output","Test":"Test☺☹Dirs","Output":"--- PASS: Test☺☹Dirs (0.01s)\n"}
index 05edf5a312f01821ed6e02b35158b20cad1be99c..bd1ed2dd9a9d9a9daef06a21f846c1215f3eceeb 100644 (file)
 === CONT  Test☺☹/2
 --- PASS: TestTags (0.00s)
     --- PASS: TestTags/x_testtag_y (0.04s)
-       vet_test.go:187: -tags=x testtag y
+        vet_test.go:187: -tags=x testtag y
     --- PASS: TestTags/x,testtag,y (0.04s)
-       vet_test.go:187: -tags=x,testtag,y
+        vet_test.go:187: -tags=x,testtag,y
     --- PASS: TestTags/testtag (0.04s)
-       vet_test.go:187: -tags=testtag
+        vet_test.go:187: -tags=testtag
 === CONT  Test☺☹/1
 === CONT  Test☺☹Dirs/testingpkg
 === CONT  Test☺☹Dirs/buildtag
 === CONT  Test☺☹Dirs/cgo
 --- PASS: Test☺☹ (0.39s)
     --- PASS: Test☺☹/5 (0.07s)
-       vet_test.go:114: φιλεσ: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
+        vet_test.go:114: φιλεσ: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
     --- PASS: Test☺☹/3 (0.07s)
-       vet_test.go:114: φιλεσ: ["testdata/composite.go" "testdata/nilfunc.go"]
+        vet_test.go:114: φιλεσ: ["testdata/composite.go" "testdata/nilfunc.go"]
     --- PASS: Test☺☹/6 (0.07s)
-       vet_test.go:114: φιλεσ: ["testdata/copylock_range.go" "testdata/shadow.go"]
+        vet_test.go:114: φιλεσ: ["testdata/copylock_range.go" "testdata/shadow.go"]
     --- PASS: Test☺☹/2 (0.07s)
-       vet_test.go:114: φιλεσ: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
+        vet_test.go:114: φιλεσ: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
     --- PASS: Test☺☹/0 (0.13s)
-       vet_test.go:114: φιλεσ: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
+        vet_test.go:114: φιλεσ: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
     --- PASS: Test☺☹/4 (0.16s)
-       vet_test.go:114: φιλεσ: ["testdata/copylock.go" "testdata/print.go"]
+        vet_test.go:114: φιλεσ: ["testdata/copylock.go" "testdata/print.go"]
     --- PASS: Test☺☹/1 (0.07s)
-       vet_test.go:114: φιλεσ: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
+        vet_test.go:114: φιλεσ: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
     --- PASS: Test☺☹/7 (0.19s)
-       vet_test.go:114: φιλεσ: ["testdata/deadcode.go" "testdata/shift.go"]
+        vet_test.go:114: φιλεσ: ["testdata/deadcode.go" "testdata/shift.go"]
 --- PASS: Test☺☹Dirs (0.01s)
     --- PASS: Test☺☹Dirs/testingpkg (0.06s)
     --- PASS: Test☺☹Dirs/divergent (0.05s)
index 8c5921d686f6a399f8f53759ae43451df8532d98..2558d61e7471ab5e99de6391ca793e65f9e4bb19 100644 (file)
 {"Action":"output","Test":"TestVet/2","Output":"=== CONT  TestVet/2\n"}
 {"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
 {"Action":"output","Test":"TestTags/x_testtag_y","Output":"    --- PASS: TestTags/x_testtag_y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"    \tvet_test.go:187: -tags=x testtag y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"        vet_test.go:187: -tags=x testtag y\n"}
 {"Action":"pass","Test":"TestTags/x_testtag_y"}
 {"Action":"output","Test":"TestTags/x,testtag,y","Output":"    --- PASS: TestTags/x,testtag,y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"    \tvet_test.go:187: -tags=x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"        vet_test.go:187: -tags=x,testtag,y\n"}
 {"Action":"pass","Test":"TestTags/x,testtag,y"}
 {"Action":"output","Test":"TestTags/testtag","Output":"    --- PASS: TestTags/testtag (0.04s)\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":"    \tvet_test.go:187: -tags=testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"        vet_test.go:187: -tags=testtag\n"}
 {"Action":"pass","Test":"TestTags/testtag"}
 {"Action":"pass","Test":"TestTags"}
 {"Action":"cont","Test":"TestVet/1"}
 {"Action":"output","Test":"TestVetDirs/cgo","Output":"=== CONT  TestVetDirs/cgo\n"}
 {"Action":"output","Test":"TestVet","Output":"--- PASS: TestVet (0.39s)\n"}
 {"Action":"output","Test":"TestVet/5","Output":"    --- PASS: TestVet/5 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/5","Output":"    \tvet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
+{"Action":"output","Test":"TestVet/5","Output":"        vet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
 {"Action":"pass","Test":"TestVet/5"}
 {"Action":"output","Test":"TestVet/3","Output":"    --- PASS: TestVet/3 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/3","Output":"    \tvet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
+{"Action":"output","Test":"TestVet/3","Output":"        vet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
 {"Action":"pass","Test":"TestVet/3"}
 {"Action":"output","Test":"TestVet/6","Output":"    --- PASS: TestVet/6 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/6","Output":"    \tvet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
+{"Action":"output","Test":"TestVet/6","Output":"        vet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
 {"Action":"pass","Test":"TestVet/6"}
 {"Action":"output","Test":"TestVet/2","Output":"    --- PASS: TestVet/2 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/2","Output":"    \tvet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
+{"Action":"output","Test":"TestVet/2","Output":"        vet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
 {"Action":"pass","Test":"TestVet/2"}
 {"Action":"output","Test":"TestVet/0","Output":"    --- PASS: TestVet/0 (0.13s)\n"}
-{"Action":"output","Test":"TestVet/0","Output":"    \tvet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
+{"Action":"output","Test":"TestVet/0","Output":"        vet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
 {"Action":"pass","Test":"TestVet/0"}
 {"Action":"output","Test":"TestVet/4","Output":"    --- PASS: TestVet/4 (0.16s)\n"}
-{"Action":"output","Test":"TestVet/4","Output":"    \tvet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
+{"Action":"output","Test":"TestVet/4","Output":"        vet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
 {"Action":"pass","Test":"TestVet/4"}
 {"Action":"output","Test":"TestVet/1","Output":"    --- PASS: TestVet/1 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/1","Output":"    \tvet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
+{"Action":"output","Test":"TestVet/1","Output":"        vet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
 {"Action":"pass","Test":"TestVet/1"}
 {"Action":"output","Test":"TestVet/7","Output":"    --- PASS: TestVet/7 (0.19s)\n"}
-{"Action":"output","Test":"TestVet/7","Output":"    \tvet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
+{"Action":"output","Test":"TestVet/7","Output":"        vet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
 {"Action":"pass","Test":"TestVet/7"}
 {"Action":"pass","Test":"TestVet"}
 {"Action":"output","Test":"TestVetDirs","Output":"--- PASS: TestVetDirs (0.01s)\n"}
index 3389559cb81bebc5853c06e98048e4f6d8ea09be..59d187e0a33b637e695f25e1838f6a8e97ef2c0f 100644 (file)
 === CONT  TestVet/2
 --- PASS: TestTags (0.00s)
     --- PASS: TestTags/x_testtag_y (0.04s)
-       vet_test.go:187: -tags=x testtag y
+        vet_test.go:187: -tags=x testtag y
     --- PASS: TestTags/x,testtag,y (0.04s)
-       vet_test.go:187: -tags=x,testtag,y
+        vet_test.go:187: -tags=x,testtag,y
     --- PASS: TestTags/testtag (0.04s)
-       vet_test.go:187: -tags=testtag
+        vet_test.go:187: -tags=testtag
 === CONT  TestVet/1
 === CONT  TestVetDirs/testingpkg
 === CONT  TestVetDirs/buildtag
 === CONT  TestVetDirs/cgo
 --- PASS: TestVet (0.39s)
     --- PASS: TestVet/5 (0.07s)
-       vet_test.go:114: files: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
+        vet_test.go:114: files: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
     --- PASS: TestVet/3 (0.07s)
-       vet_test.go:114: files: ["testdata/composite.go" "testdata/nilfunc.go"]
+        vet_test.go:114: files: ["testdata/composite.go" "testdata/nilfunc.go"]
     --- PASS: TestVet/6 (0.07s)
-       vet_test.go:114: files: ["testdata/copylock_range.go" "testdata/shadow.go"]
+        vet_test.go:114: files: ["testdata/copylock_range.go" "testdata/shadow.go"]
     --- PASS: TestVet/2 (0.07s)
-       vet_test.go:114: files: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
+        vet_test.go:114: files: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
     --- PASS: TestVet/0 (0.13s)
-       vet_test.go:114: files: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
+        vet_test.go:114: files: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
     --- PASS: TestVet/4 (0.16s)
-       vet_test.go:114: files: ["testdata/copylock.go" "testdata/print.go"]
+        vet_test.go:114: files: ["testdata/copylock.go" "testdata/print.go"]
     --- PASS: TestVet/1 (0.07s)
-       vet_test.go:114: files: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
+        vet_test.go:114: files: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
     --- PASS: TestVet/7 (0.19s)
-       vet_test.go:114: files: ["testdata/deadcode.go" "testdata/shift.go"]
+        vet_test.go:114: files: ["testdata/deadcode.go" "testdata/shift.go"]
 --- PASS: TestVetDirs (0.01s)
     --- PASS: TestVetDirs/testingpkg (0.06s)
     --- PASS: TestVetDirs/divergent (0.05s)
index 0385d8f246c358a39185e3c8642c07ff2aa16184..57a874193e311cb19797dee89f16055fde81edeb 100644 (file)
@@ -118,12 +118,16 @@ func main() {
                w := &countWriter{0, c}
                cmd.Stdout = w
                cmd.Stderr = w
-               if err := cmd.Run(); err != nil {
+               err := cmd.Run()
+               if err != nil {
                        if w.n > 0 {
                                // Assume command printed why it failed.
                        } else {
                                fmt.Fprintf(c, "test2json: %v\n", err)
                        }
+               }
+               c.Exited(err)
+               if err != nil {
                        c.Close()
                        os.Exit(1)
                }
index 604607f774a031e427f74ec70dbc4ee4e49ffcb6..09de299ff71781f09e173acc72dc60705e2f1b37 100644 (file)
@@ -41,7 +41,7 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
                        // use copy_file_range(2) again.
                        atomic.StoreInt32(&copyFileRangeSupported, 0)
                        return 0, false, nil
-               case syscall.EXDEV, syscall.EINVAL:
+               case syscall.EXDEV, syscall.EINVAL, syscall.EOPNOTSUPP, syscall.EPERM:
                        // Prior to Linux 5.3, it was not possible to
                        // copy_file_range across file systems. Similarly to
                        // the ENOSYS case above, if we see EXDEV, we have
@@ -52,6 +52,14 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
                        // dst or src refer to a pipe rather than a regular
                        // file. This is another case where no data has been
                        // transfered, so we consider it unhandled.
+                       //
+                       // If the file is on NFS, we can see EOPNOTSUPP.
+                       // See issue #40731.
+                       //
+                       // If the process is running inside a Docker container,
+                       // we might see EPERM instead of ENOSYS. See issue
+                       // #40893. Since EPERM might also be a legitimate error,
+                       // don't mark copy_file_range(2) as unsupported.
                        return 0, false, nil
                case nil:
                        if n == 0 {
index 9474175f1791eba414d2443909580c16ed0c7405..61de6165f6199917bd796bd62a88af4cbd3bfad5 100644 (file)
@@ -163,10 +163,12 @@ func Serve(handler http.Handler) error {
 }
 
 type response struct {
-       req        *http.Request
-       header     http.Header
-       bufw       *bufio.Writer
-       headerSent bool
+       req            *http.Request
+       header         http.Header
+       code           int
+       wroteHeader    bool
+       wroteCGIHeader bool
+       bufw           *bufio.Writer
 }
 
 func (r *response) Flush() {
@@ -178,26 +180,38 @@ func (r *response) Header() http.Header {
 }
 
 func (r *response) Write(p []byte) (n int, err error) {
-       if !r.headerSent {
+       if !r.wroteHeader {
                r.WriteHeader(http.StatusOK)
        }
+       if !r.wroteCGIHeader {
+               r.writeCGIHeader(p)
+       }
        return r.bufw.Write(p)
 }
 
 func (r *response) WriteHeader(code int) {
-       if r.headerSent {
+       if r.wroteHeader {
                // Note: explicitly using Stderr, as Stdout is our HTTP output.
                fmt.Fprintf(os.Stderr, "CGI attempted to write header twice on request for %s", r.req.URL)
                return
        }
-       r.headerSent = true
-       fmt.Fprintf(r.bufw, "Status: %d %s\r\n", code, http.StatusText(code))
+       r.wroteHeader = true
+       r.code = code
+}
 
-       // Set a default Content-Type
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+       if r.wroteCGIHeader {
+               return
+       }
+       r.wroteCGIHeader = true
+       fmt.Fprintf(r.bufw, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
        if _, hasType := r.header["Content-Type"]; !hasType {
-               r.header.Add("Content-Type", "text/html; charset=utf-8")
+               r.header.Set("Content-Type", http.DetectContentType(p))
        }
-
        r.header.Write(r.bufw)
        r.bufw.WriteString("\r\n")
        r.bufw.Flush()
index 14e0af475f5af90903a8f4668d44a173697eacea..f6ecb6eb80f24d3e163dea5d046c984f8590c4ce 100644 (file)
@@ -7,6 +7,11 @@
 package cgi
 
 import (
+       "bufio"
+       "bytes"
+       "net/http"
+       "net/http/httptest"
+       "strings"
        "testing"
 )
 
@@ -148,3 +153,67 @@ func TestRequestWithoutRemotePort(t *testing.T) {
                t.Errorf("RemoteAddr: got %q; want %q", g, e)
        }
 }
+
+type countingWriter int
+
+func (c *countingWriter) Write(p []byte) (int, error) {
+       *c += countingWriter(len(p))
+       return len(p), nil
+}
+func (c *countingWriter) WriteString(p string) (int, error) {
+       *c += countingWriter(len(p))
+       return len(p), nil
+}
+
+func TestResponse(t *testing.T) {
+       var tests = []struct {
+               name   string
+               body   string
+               wantCT string
+       }{
+               {
+                       name:   "no body",
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "html",
+                       body:   "<html><head><title>test page</title></head><body>This is a body</body></html>",
+                       wantCT: "text/html; charset=utf-8",
+               },
+               {
+                       name:   "text",
+                       body:   strings.Repeat("gopher", 86),
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "jpg",
+                       body:   "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+                       wantCT: "image/jpeg",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       var buf bytes.Buffer
+                       resp := response{
+                               req:    httptest.NewRequest("GET", "/", nil),
+                               header: http.Header{},
+                               bufw:   bufio.NewWriter(&buf),
+                       }
+                       n, err := resp.Write([]byte(tt.body))
+                       if err != nil {
+                               t.Errorf("Write: unexpected %v", err)
+                       }
+                       if want := len(tt.body); n != want {
+                               t.Errorf("reported short Write: got %v want %v", n, want)
+                       }
+                       resp.writeCGIHeader(nil)
+                       resp.Flush()
+                       if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+                               t.Errorf("wrong content-type: got %q, want %q", got, tt.wantCT)
+                       }
+                       if !bytes.HasSuffix(buf.Bytes(), []byte(tt.body)) {
+                               t.Errorf("body was not correctly written")
+                       }
+               })
+       }
+}
index 32d59c09a3c52be726386978852960b3677c45b0..295c3b82d404ccd9bc520a0fb5cea2d90bfd5e67 100644 (file)
@@ -16,7 +16,9 @@ import (
        "io"
        "net/http"
        "net/http/httptest"
+       "net/url"
        "os"
+       "strings"
        "testing"
        "time"
 )
@@ -52,7 +54,7 @@ func TestHostingOurselves(t *testing.T) {
        }
        replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
 
-       if expected, got := "text/html; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
+       if expected, got := "text/plain; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
                t.Errorf("got a Content-Type of %q; expected %q", got, expected)
        }
        if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
@@ -152,6 +154,51 @@ func TestChildOnlyHeaders(t *testing.T) {
        }
 }
 
+func TestChildContentType(t *testing.T) {
+       testenv.MustHaveExec(t)
+
+       h := &Handler{
+               Path: os.Args[0],
+               Root: "/test.go",
+               Args: []string{"-test.run=TestBeChildCGIProcess"},
+       }
+       var tests = []struct {
+               name   string
+               body   string
+               wantCT string
+       }{
+               {
+                       name:   "no body",
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "html",
+                       body:   "<html><head><title>test page</title></head><body>This is a body</body></html>",
+                       wantCT: "text/html; charset=utf-8",
+               },
+               {
+                       name:   "text",
+                       body:   strings.Repeat("gopher", 86),
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "jpg",
+                       body:   "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+                       wantCT: "image/jpeg",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       expectedMap := map[string]string{"_body": tt.body}
+                       req := fmt.Sprintf("GET /test.go?exact-body=%s HTTP/1.0\nHost: example.com\n\n", url.QueryEscape(tt.body))
+                       replay := runCgiTest(t, h, req, expectedMap)
+                       if got := replay.Header().Get("Content-Type"); got != tt.wantCT {
+                               t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
+                       }
+               })
+       }
+}
+
 // golang.org/issue/7198
 func Test500WithNoHeaders(t *testing.T)     { want500Test(t, "/immediate-disconnect") }
 func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
@@ -203,6 +250,10 @@ func TestBeChildCGIProcess(t *testing.T) {
                if req.FormValue("no-body") == "1" {
                        return
                }
+               if eb, ok := req.Form["exact-body"]; ok {
+                       io.WriteString(rw, eb[0])
+                       return
+               }
                if req.FormValue("write-forever") == "1" {
                        io.Copy(rw, neverEnding('a'))
                        for {
index 30a6b2ce2dfe8335efce24b38c274bc0476fd8ed..a31273b3eca7a64216da830dae33fb0fc9005ab1 100644 (file)
@@ -74,10 +74,12 @@ func (r *request) parseParams() {
 
 // response implements http.ResponseWriter.
 type response struct {
-       req         *request
-       header      http.Header
-       w           *bufWriter
-       wroteHeader bool
+       req            *request
+       header         http.Header
+       code           int
+       wroteHeader    bool
+       wroteCGIHeader bool
+       w              *bufWriter
 }
 
 func newResponse(c *child, req *request) *response {
@@ -92,11 +94,14 @@ func (r *response) Header() http.Header {
        return r.header
 }
 
-func (r *response) Write(data []byte) (int, error) {
+func (r *response) Write(p []byte) (n int, err error) {
        if !r.wroteHeader {
                r.WriteHeader(http.StatusOK)
        }
-       return r.w.Write(data)
+       if !r.wroteCGIHeader {
+               r.writeCGIHeader(p)
+       }
+       return r.w.Write(p)
 }
 
 func (r *response) WriteHeader(code int) {
@@ -104,22 +109,34 @@ func (r *response) WriteHeader(code int) {
                return
        }
        r.wroteHeader = true
+       r.code = code
        if code == http.StatusNotModified {
                // Must not have body.
                r.header.Del("Content-Type")
                r.header.Del("Content-Length")
                r.header.Del("Transfer-Encoding")
-       } else if r.header.Get("Content-Type") == "" {
-               r.header.Set("Content-Type", "text/html; charset=utf-8")
        }
-
        if r.header.Get("Date") == "" {
                r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
        }
+}
 
-       fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+       if r.wroteCGIHeader {
+               return
+       }
+       r.wroteCGIHeader = true
+       fmt.Fprintf(r.w, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
+       if _, hasType := r.header["Content-Type"]; r.code != http.StatusNotModified && !hasType {
+               r.header.Set("Content-Type", http.DetectContentType(p))
+       }
        r.header.Write(r.w)
        r.w.WriteString("\r\n")
+       r.w.Flush()
 }
 
 func (r *response) Flush() {
@@ -290,6 +307,8 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
                httpReq = httpReq.WithContext(envVarCtx)
                c.handler.ServeHTTP(r, httpReq)
        }
+       // Make sure we serve something even if nothing was written to r
+       r.Write(nil)
        r.Close()
        c.mu.Lock()
        delete(c.requests, req.reqId)
index e9d2b34023c81a392c6b1662eaff5a162f20cbfb..59246c26cc87182ae8f92d08d22b4f8ca4292cfb 100644 (file)
@@ -10,6 +10,7 @@ import (
        "io"
        "io/ioutil"
        "net/http"
+       "strings"
        "testing"
 )
 
@@ -344,3 +345,55 @@ func TestChildServeReadsEnvVars(t *testing.T) {
                <-done
        }
 }
+
+func TestResponseWriterSniffsContentType(t *testing.T) {
+       t.Skip("this test is flaky, see Issue 41167")
+       var tests = []struct {
+               name   string
+               body   string
+               wantCT string
+       }{
+               {
+                       name:   "no body",
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "html",
+                       body:   "<html><head><title>test page</title></head><body>This is a body</body></html>",
+                       wantCT: "text/html; charset=utf-8",
+               },
+               {
+                       name:   "text",
+                       body:   strings.Repeat("gopher", 86),
+                       wantCT: "text/plain; charset=utf-8",
+               },
+               {
+                       name:   "jpg",
+                       body:   "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+                       wantCT: "image/jpeg",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       input := make([]byte, len(streamFullRequestStdin))
+                       copy(input, streamFullRequestStdin)
+                       rc := nopWriteCloser{bytes.NewBuffer(input)}
+                       done := make(chan bool)
+                       var resp *response
+                       c := newChild(rc, http.HandlerFunc(func(
+                               w http.ResponseWriter,
+                               r *http.Request,
+                       ) {
+                               io.WriteString(w, tt.body)
+                               resp = w.(*response)
+                               done <- true
+                       }))
+                       defer c.cleanUp()
+                       go c.serve()
+                       <-done
+                       if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+                               t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
+                       }
+               })
+       }
+}
index 6833cfaec11c1803dda89b5a8a68663cd9816764..09fb794005a9b06b18b2063417364cc567b82cea 100644 (file)
@@ -279,9 +279,6 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
                if p.consume(',') {
                        continue
                }
-               if p.empty() {
-                       break
-               }
 
                addrs, err := p.parseAddress(true)
                if err != nil {
@@ -295,9 +292,17 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
                if p.empty() {
                        break
                }
-               if !p.consume(',') {
+               if p.peek() != ',' {
                        return nil, errors.New("mail: expected comma")
                }
+
+               // Skip empty entries for obs-addr-list.
+               for p.consume(',') {
+                       p.skipSpace()
+               }
+               if p.empty() {
+                       break
+               }
        }
        return list, nil
 }
index 75db767547334b9179a93790a2aeff859e0b73f5..67e3643aeb774cfb099fcfcba189c991a702ad57 100644 (file)
@@ -445,6 +445,19 @@ func TestAddressParsing(t *testing.T) {
                                },
                        },
                },
+               {
+                       ` , joe@where.test,,John <jdoe@one.test>,,`,
+                       []*Address{
+                               {
+                                       Name:    "",
+                                       Address: "joe@where.test",
+                               },
+                               {
+                                       Name:    "John",
+                                       Address: "jdoe@one.test",
+                               },
+                       },
+               },
                {
                        `Group1: <addr1@example.com>;, Group 2: addr2@example.com;, John <addr3@example.com>`,
                        []*Address{
@@ -1067,3 +1080,22 @@ func TestAddressFormattingAndParsing(t *testing.T) {
                }
        }
 }
+
+func TestEmptyAddress(t *testing.T) {
+       parsed, err := ParseAddress("")
+       if parsed != nil || err == nil {
+               t.Errorf(`ParseAddress("") = %v, %v, want nil, error`, parsed, err)
+       }
+       list, err := ParseAddressList("")
+       if len(list) > 0 || err == nil {
+               t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err)
+       }
+       list, err = ParseAddressList(",")
+       if len(list) > 0 || err == nil {
+               t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err)
+       }
+       list, err = ParseAddressList("a@b c@d")
+       if len(list) > 0 || err == nil {
+               t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err)
+       }
+}
index 76aa2cdb2ba762ac816bc2df7d69cf37c2085641..bd2d00f117a7d0e2e6780de0b59c7be6e9746833 100644 (file)
@@ -31,6 +31,7 @@ func TestCheckPtr(t *testing.T) {
                {"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"},
                {"CheckPtrAlignmentNoPtr", ""},
                {"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
+               {"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
                {"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
                {"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
        }
index 425ca8dd93f680ac7fc9c9b57c64d06fc0a7cd93..32378a96277c7199c3eb894c2c5a97e69316ef74 100644 (file)
@@ -18,19 +18,29 @@ func getLockRank(l *mutex) lockRank {
        return 0
 }
 
+// The following functions may be called in nosplit context.
+// Nosplit is not strictly required for lockWithRank, unlockWithRank
+// and lockWithRankMayAcquire, but these nosplit annotations must
+// be kept consistent with the equivalent functions in lockrank_on.go.
+
+//go:nosplit
 func lockWithRank(l *mutex, rank lockRank) {
        lock2(l)
 }
 
+//go:nosplit
 func acquireLockRank(rank lockRank) {
 }
 
+//go:nosplit
 func unlockWithRank(l *mutex) {
        unlock2(l)
 }
 
+//go:nosplit
 func releaseLockRank(rank lockRank) {
 }
 
+//go:nosplit
 func lockWithRankMayAcquire(l *mutex, rank lockRank) {
 }
index 45e6fb1aa53f6c463ad7a8196439505372a00526..e0a2794f4c1da108a7883285a20526e3738bebed 100644 (file)
@@ -10,6 +10,7 @@ func init() {
        register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
        register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
        register("CheckPtrArithmetic", CheckPtrArithmetic)
+       register("CheckPtrArithmetic2", CheckPtrArithmetic2)
        register("CheckPtrSize", CheckPtrSize)
        register("CheckPtrSmall", CheckPtrSmall)
 }
@@ -32,6 +33,13 @@ func CheckPtrArithmetic() {
        sink2 = (*int)(unsafe.Pointer(i))
 }
 
+func CheckPtrArithmetic2() {
+       var x [2]int64
+       p := unsafe.Pointer(&x[1])
+       var one uintptr = 1
+       sink2 = unsafe.Pointer(uintptr(p) & ^one)
+}
+
 func CheckPtrSize() {
        p := new(int64)
        sink2 = p
index a61e2ebdd67f72c07773eff50946dad1db6cbe74..9ad25353ff48cef7c541de24e3382c346dc44f61 100644 (file)
@@ -274,6 +274,7 @@ func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
                e, ok = read.m[key]
                if !ok && read.amended {
                        e, ok = m.dirty[key]
+                       delete(m.dirty, key)
                        // Regardless of whether the entry was present, record a miss: this key
                        // will take the slow path until the dirty map is promoted to the read
                        // map.
index 4ae989a6d5d8175108f3119888f70888ec252290..7f163caa5c95d111845844e41fa401065b4a9766 100644 (file)
@@ -9,6 +9,7 @@ import (
        "reflect"
        "runtime"
        "sync"
+       "sync/atomic"
        "testing"
        "testing/quick"
 )
@@ -171,3 +172,26 @@ func TestConcurrentRange(t *testing.T) {
                }
        }
 }
+
+func TestIssue40999(t *testing.T) {
+       var m sync.Map
+
+       // Since the miss-counting in missLocked (via Delete)
+       // compares the miss count with len(m.dirty),
+       // add an initial entry to bias len(m.dirty) above the miss count.
+       m.Store(nil, struct{}{})
+
+       var finalized uint32
+
+       // Set finalizers that count for collected keys. A non-zero count
+       // indicates that keys have not been leaked.
+       for atomic.LoadUint32(&finalized) == 0 {
+               p := new(int)
+               runtime.SetFinalizer(p, func(*int) {
+                       atomic.AddUint32(&finalized, 1)
+               })
+               m.Store(p, struct{}{})
+               m.Delete(p)
+               runtime.GC()
+       }
+}
index dee77f747c01effb3ae27bfdb1876d056ebfee27..fe6929d1ba0449b200479eb3a29bc6a957605139 100644 (file)
@@ -357,10 +357,19 @@ func (p *testPrinter) Fprint(w io.Writer, testName, out string) {
        defer p.lastNameMu.Unlock()
 
        if !p.chatty ||
-               strings.HasPrefix(out, "--- PASS") ||
-               strings.HasPrefix(out, "--- FAIL") ||
-               strings.HasPrefix(out, "=== CONT") ||
-               strings.HasPrefix(out, "=== RUN") {
+               strings.HasPrefix(out, "--- PASS: ") ||
+               strings.HasPrefix(out, "--- FAIL: ") ||
+               strings.HasPrefix(out, "--- SKIP: ") ||
+               strings.HasPrefix(out, "=== RUN   ") ||
+               strings.HasPrefix(out, "=== CONT  ") ||
+               strings.HasPrefix(out, "=== PAUSE ") {
+               // If we're buffering test output (!p.chatty), we don't really care which
+               // test is emitting which line so long as they are serialized.
+               //
+               // If the message already implies an association with a specific new test,
+               // we don't need to check what the old test name was or log an extra CONT
+               // line for it. (We're updating it anyway, and the current message already
+               // includes the test name.)
                p.lastName = testName
                fmt.Fprint(w, out)
                return
@@ -887,11 +896,15 @@ func (c *common) Cleanup(f func()) {
        c.cleanup = func() {
                if oldCleanup != nil {
                        defer func() {
+                               c.mu.Lock()
                                c.cleanupPc = oldCleanupPc
+                               c.mu.Unlock()
                                oldCleanup()
                        }()
                }
+               c.mu.Lock()
                c.cleanupName = callerName(0)
+               c.mu.Unlock()
                f()
        }
        var pc [maxStackLen]uintptr
@@ -1012,7 +1025,13 @@ func (t *T) Parallel() {
                for ; root.parent != nil; root = root.parent {
                }
                root.mu.Lock()
-               fmt.Fprintf(root.w, "=== PAUSE %s\n", t.name)
+               // Unfortunately, even though PAUSE indicates that the named test is *no
+               // longer* running, cmd/test2json interprets it as changing the active test
+               // for the purpose of log parsing. We could fix cmd/test2json, but that
+               // won't fix existing deployments of third-party tools that already shell
+               // out to older builds of cmd/test2json — so merely fixing cmd/test2json
+               // isn't enough for now.
+               printer.Fprint(root.w, t.name, fmt.Sprintf("=== PAUSE %s\n", t.name))
                root.mu.Unlock()
        }
 
index bddb1320098b340401b6a974c15552cd18bafd3d..f8de950fe2e67ad52373a17872973c3e038db224 100755 (executable)
@@ -128,7 +128,7 @@ echo ${rev} > VERSION
 (cd ${NEWDIR}/src && find . -name '*.go' -print) | while read f; do
   skip=false
   case "$f" in
-  ./cmd/buildid/* | ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/testjson/* | ./cmd/vet/* | ./cmd/internal/browser/* | ./cmd/internal/buildid/* | ./cmd/internal/edit/* | ./cmd/internal/objabi/* | ./cmd/internal/testj2on/* | ./cmd/internal/sys/* | ./cmd/vendor/golang.org/x/tools/* | ./cmd/vendor/golang.org/x/mod/* | ./cmd/vendor/golang.org/x/xerrors/* | ./cmd/vendor/golang.org/x/crypto/ed25519)
+  ./cmd/buildid/* | ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/test2json/* | ./cmd/vet/* | ./cmd/internal/browser/* | ./cmd/internal/buildid/* | ./cmd/internal/edit/* | ./cmd/internal/objabi/* | ./cmd/internal/test2json/* | ./cmd/internal/sys/* | ./cmd/vendor/golang.org/x/tools/* | ./cmd/vendor/golang.org/x/mod/* | ./cmd/vendor/golang.org/x/xerrors/* | ./cmd/vendor/golang.org/x/crypto/ed25519)
     ;;
   ./cmd/*)
     skip=true
@@ -150,7 +150,7 @@ done
 (cd ${NEWDIR}/src && find . -name testdata -print) | while read d; do
   skip=false
   case "$d" in
-  ./cmd/buildid/* | ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/testjson/* | ./cmd/vet/* | ./cmd/internal/browser/* | ./cmd/internal/buildid/* | ./cmd/internal/diff/* | ./cmd/internal/edit/* | ./cmd/internal/objabi/* | ./cmd/internal/testj2on/* | ./cmd/internal/sys/* | ./cmd/vendor/golang.org/x/tools/*)
+  ./cmd/buildid/* | ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/test2json/* | ./cmd/vet/* | ./cmd/internal/browser/* | ./cmd/internal/buildid/* | ./cmd/internal/diff/* | ./cmd/internal/edit/* | ./cmd/internal/objabi/* | ./cmd/internal/test2json/* | ./cmd/internal/sys/* | ./cmd/vendor/golang.org/x/tools/*)
     ;;
   ./cmd/*)
     skip=true