I have committed a patch to libgo to update to the go1.8rc2 release candidate.
This uncovered a bug in the calculation of the hash code for reflect.FuncOf, which is fixed by this patch. I noticed while doing the merge that somewhere along the way a bunch of testdata files were dropped. I added them here, although they are not new in 1.8rc2. The new testdata files are largely uninteresting, so in this e-mail message I've only included the changes to non-test files. Committed to mainline. Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 244824) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -0655e25d8e4acfac50c6b1422dc32eca3e30803a +fb609ff6d940768cf4db4ab7deb93b2ab686e45d The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: libgo/MERGE =================================================================== --- libgo/MERGE (revision 244456) +++ libgo/MERGE (working copy) @@ -1,4 +1,4 @@ -3de6e96e4b8147f5267a2e8218a7c780b09a434f +59f181b6fda68ece22882945853ca2df9dbf1c88 The first line of this file holds the git revision number of the last merge done from the master library sources. Index: libgo/VERSION =================================================================== --- libgo/VERSION (revision 244456) +++ libgo/VERSION (working copy) @@ -1 +1 @@ -go1.8rc1 +go1.8rc2 Index: libgo/go/cmd/go/bug.go =================================================================== --- libgo/go/cmd/go/bug.go (revision 244456) +++ libgo/go/cmd/go/bug.go (working copy) @@ -20,11 +20,10 @@ import ( var cmdBug = &Command{ Run: runBug, UsageLine: "bug", - Short: "print information for bug reports", + Short: "start a bug report", Long: ` -Bug prints information that helps file effective bug reports. - -Bugs may be reported at https://golang.org/issue/new. +Bug opens the default browser and starts a new bug report. +The report includes useful system information. `, } Index: libgo/go/cmd/go/test.go =================================================================== --- libgo/go/cmd/go/test.go (revision 244456) +++ libgo/go/cmd/go/test.go (working copy) @@ -906,9 +906,13 @@ func (b *builder) test(p *Package) (buil if buildContext.GOOS == "darwin" { if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" { - t.NeedCgo = true + t.IsIOS = true + t.NeedOS = true } } + if t.TestMain == nil { + t.NeedOS = true + } for _, cp := range pmain.imports { if len(cp.coverVars) > 0 { @@ -1355,7 +1359,8 @@ type testFuncs struct { NeedTest bool ImportXtest bool NeedXtest bool - NeedCgo bool + NeedOS bool + IsIOS bool Cover []coverInfo } @@ -1456,7 +1461,7 @@ var testmainTmpl = template.Must(templat package main import ( -{{if not .TestMain}} +{{if .NeedOS}} "os" {{end}} "testing" @@ -1472,8 +1477,10 @@ import ( _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} {{end}} -{{if .NeedCgo}} +{{if .IsIOS}} + "os/signal" _ "runtime/cgo" + "syscall" {{end}} ) @@ -1535,6 +1542,32 @@ func coverRegisterFile(fileName string, {{end}} func main() { +{{if .IsIOS}} + // Send a SIGUSR2, which will be intercepted by LLDB to + // tell the test harness that installation was successful. + // See misc/ios/go_darwin_arm_exec.go. + signal.Notify(make(chan os.Signal), syscall.SIGUSR2) + syscall.Kill(0, syscall.SIGUSR2) + signal.Reset(syscall.SIGUSR2) + + // The first argument supplied to an iOS test is an offset + // suffix for the current working directory. + // Process it here, and remove it from os.Args. + const hdr = "cwdSuffix=" + if len(os.Args) < 2 || len(os.Args[1]) <= len(hdr) || os.Args[1][:len(hdr)] != hdr { + panic("iOS test not passed a working directory suffix") + } + suffix := os.Args[1][len(hdr):] + dir, err := os.Getwd() + if err != nil { + panic(err) + } + if err := os.Chdir(dir + "/" + suffix); err != nil { + panic(err) + } + os.Args = append([]string{os.Args[0]}, os.Args[2:]...) +{{end}} + {{if .CoverEnabled}} testing.RegisterCover(testing.Cover{ Mode: {{printf "%q" .CoverMode}}, Index: libgo/go/compress/bzip2/bzip2_test.go =================================================================== --- libgo/go/compress/bzip2/bzip2_test.go (revision 244166) +++ libgo/go/compress/bzip2/bzip2_test.go (working copy) @@ -204,12 +204,6 @@ func TestMTF(t *testing.T) { } } -var ( - digits = mustLoadFile("testdata/e.txt.bz2") - twain = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2") - random = mustLoadFile("testdata/random.data.bz2") -) - func benchmarkDecode(b *testing.B, compressed []byte) { // Determine the uncompressed size of testfile. uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed))) @@ -227,6 +221,18 @@ func benchmarkDecode(b *testing.B, compr } } -func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) } -func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) } -func BenchmarkDecodeRand(b *testing.B) { benchmarkDecode(b, random) } +func BenchmarkDecodeDigits(b *testing.B) { + digits := mustLoadFile("testdata/e.txt.bz2") + b.ResetTimer() + benchmarkDecode(b, digits) +} +func BenchmarkDecodeTwain(b *testing.B) { + twain := mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2") + b.ResetTimer() + benchmarkDecode(b, twain) +} +func BenchmarkDecodeRand(b *testing.B) { + random := mustLoadFile("testdata/random.data.bz2") + b.ResetTimer() + benchmarkDecode(b, random) +} Index: libgo/go/compress/flate/deflate.go =================================================================== --- libgo/go/compress/flate/deflate.go (revision 244456) +++ libgo/go/compress/flate/deflate.go (working copy) @@ -136,14 +136,17 @@ func (d *compressor) fillDeflate(b []byt delta := d.hashOffset - 1 d.hashOffset -= delta d.chainHead -= delta - for i, v := range d.hashPrev { + + // Iterate over slices instead of arrays to avoid copying + // the entire table onto the stack (Issue #18625). + for i, v := range d.hashPrev[:] { if int(v) > delta { d.hashPrev[i] = uint32(int(v) - delta) } else { d.hashPrev[i] = 0 } } - for i, v := range d.hashHead { + for i, v := range d.hashHead[:] { if int(v) > delta { d.hashHead[i] = uint32(int(v) - delta) } else { Index: libgo/go/compress/flate/deflate_test.go =================================================================== --- libgo/go/compress/flate/deflate_test.go (revision 244456) +++ libgo/go/compress/flate/deflate_test.go (working copy) @@ -12,6 +12,7 @@ import ( "io" "io/ioutil" "reflect" + "runtime/debug" "sync" "testing" ) @@ -864,3 +865,33 @@ func TestBestSpeedMaxMatchOffset(t *test } } } + +func TestMaxStackSize(t *testing.T) { + // This test must not run in parallel with other tests as debug.SetMaxStack + // affects all goroutines. + n := debug.SetMaxStack(1 << 16) + defer debug.SetMaxStack(n) + + var wg sync.WaitGroup + defer wg.Wait() + + b := make([]byte, 1<<20) + for level := HuffmanOnly; level <= BestCompression; level++ { + // Run in separate goroutine to increase probability of stack regrowth. + wg.Add(1) + go func(level int) { + defer wg.Done() + zw, err := NewWriter(ioutil.Discard, level) + if err != nil { + t.Errorf("level %d, NewWriter() = %v, want nil", level, err) + } + if n, err := zw.Write(b); n != len(b) || err != nil { + t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b)) + } + if err := zw.Close(); err != nil { + t.Errorf("level %d, Close() = %v, want nil", level, err) + } + zw.Reset(ioutil.Discard) + }(level) + } +} Index: libgo/go/compress/flate/deflatefast.go =================================================================== --- libgo/go/compress/flate/deflatefast.go (revision 244456) +++ libgo/go/compress/flate/deflatefast.go (working copy) @@ -60,7 +60,7 @@ func newDeflateFast() *deflateFast { func (e *deflateFast) encode(dst []token, src []byte) []token { // Ensure that e.cur doesn't wrap. if e.cur > 1<<30 { - *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]} + e.resetAll() } // This check isn't in the Snappy implementation, but there, the caller @@ -265,6 +265,21 @@ func (e *deflateFast) reset() { // Protect against e.cur wraparound. if e.cur > 1<<30 { - *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]} + e.resetAll() + } +} + +// resetAll resets the deflateFast struct and is only called in rare +// situations to prevent integer overflow. It manually resets each field +// to avoid causing large stack growth. +// +// See https://golang.org/issue/18636. +func (e *deflateFast) resetAll() { + // This is equivalent to: + // *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]} + e.cur = maxStoreBlockSize + e.prev = e.prev[:0] + for i := range e.table { + e.table[i] = tableEntry{} } } Index: libgo/go/compress/gzip/issue14937_test.go =================================================================== --- libgo/go/compress/gzip/issue14937_test.go (revision 244456) +++ libgo/go/compress/gzip/issue14937_test.go (working copy) @@ -9,11 +9,17 @@ import ( "testing" ) -// Per golang.org/issue/14937, check that every .gz file -// in the tree has a zero mtime. +// TestGZIPFilesHaveZeroMTimes checks that every .gz file in the tree +// has a zero MTIME. This is a requirement for the Debian maintainers +// to be able to have deterministic packages. +// +// See https://golang.org/issue/14937. func TestGZIPFilesHaveZeroMTimes(t *testing.T) { - if testing.Short() && testenv.Builder() == "" { - t.Skip("skipping in short mode") + // To avoid spurious false positives due to untracked GZIP files that + // may be in the user's GOROOT (Issue 18604), we only run this test on + // the builders, which should have a clean checkout of the tree. + if testenv.Builder() == "" { + t.Skip("skipping test on non-builder") } goroot, err := filepath.EvalSymlinks(runtime.GOROOT()) if err != nil { Index: libgo/go/crypto/tls/cipher_suites.go =================================================================== --- libgo/go/crypto/tls/cipher_suites.go (revision 244456) +++ libgo/go/crypto/tls/cipher_suites.go (working copy) @@ -84,15 +84,15 @@ var cipherSuites = []*cipherSuite{ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil}, {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, Index: libgo/go/crypto/tls/tls.go =================================================================== --- libgo/go/crypto/tls/tls.go (revision 244456) +++ libgo/go/crypto/tls/tls.go (working copy) @@ -6,8 +6,8 @@ package tls // BUG(agl): The crypto/tls package only implements some countermeasures -// against Lucky13 attacks on CBC-mode encryption. See -// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and +// against Lucky13 attacks on CBC-mode encryption, and only on SHA1 +// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and // https://www.imperialviolet.org/2013/02/04/luckythirteen.html. import ( Index: libgo/go/crypto/x509/cert_pool.go =================================================================== --- libgo/go/crypto/x509/cert_pool.go (revision 244456) +++ libgo/go/crypto/x509/cert_pool.go (working copy) @@ -4,7 +4,11 @@ package x509 -import "encoding/pem" +import ( + "encoding/pem" + "errors" + "runtime" +) // CertPool is a set of certificates. type CertPool struct { @@ -26,6 +30,11 @@ func NewCertPool() *CertPool { // Any mutations to the returned pool are not written to disk and do // not affect any other pool. func SystemCertPool() (*CertPool, error) { + if runtime.GOOS == "windows" { + // Issue 16736, 18609: + return nil, errors.New("crypto/x509: system root pool is not available on Windows") + } + return loadSystemRoots() } Index: libgo/go/crypto/x509/root_windows.go =================================================================== --- libgo/go/crypto/x509/root_windows.go (revision 244456) +++ libgo/go/crypto/x509/root_windows.go (working copy) @@ -226,6 +226,11 @@ func (c *Certificate) systemVerify(opts } func loadSystemRoots() (*CertPool, error) { + // TODO: restore this functionality on Windows. We tried to do + // it in Go 1.8 but had to revert it. See Issue 18609. + // Returning (nil, nil) was the old behavior, prior to CL 30578. + return nil, nil + const CRYPT_E_NOT_FOUND = 0x80092004 store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT")) Index: libgo/go/crypto/x509/x509_test.go =================================================================== --- libgo/go/crypto/x509/x509_test.go (revision 244456) +++ libgo/go/crypto/x509/x509_test.go (working copy) @@ -24,6 +24,7 @@ import ( "net" "os/exec" "reflect" + "runtime" "strings" "testing" "time" @@ -1477,6 +1478,9 @@ func TestMultipleRDN(t *testing.T) { } func TestSystemCertPool(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not implemented on Windows; Issue 16736, 18609") + } _, err := SystemCertPool() if err != nil { t.Fatal(err) Index: libgo/go/go/ast/scope.go =================================================================== --- libgo/go/go/ast/scope.go (revision 244166) +++ libgo/go/go/ast/scope.go (working copy) @@ -70,10 +70,8 @@ func (s *Scope) String() string { // The Data fields contains object-specific data: // // Kind Data type Data value -// Pkg *types.Package package scope +// Pkg *Scope package scope // Con int iota for the respective declaration -// Con != nil constant value -// Typ *Scope (used as method scope during type checking - transient) // type Object struct { Kind ObjKind Index: libgo/go/go/doc/doc_test.go =================================================================== --- libgo/go/go/doc/doc_test.go (revision 244166) +++ libgo/go/go/doc/doc_test.go (working copy) @@ -25,7 +25,7 @@ var files = flag.String("files", "", "co const dataDir = "testdata" -var templateTxt = readTemplate("template.txt") +var templateTxt *template.Template func readTemplate(filename string) *template.Template { t := template.New(filename) @@ -96,6 +96,9 @@ func test(t *testing.T, mode Mode) { if err != nil { t.Fatal(err) } + if templateTxt == nil { + templateTxt = readTemplate("template.txt") + } // test packages for _, pkg := range pkgs { Index: libgo/go/go/parser/performance_test.go =================================================================== --- libgo/go/go/parser/performance_test.go (revision 244166) +++ libgo/go/go/parser/performance_test.go (working copy) @@ -10,17 +10,12 @@ import ( "testing" ) -var src = readFile("parser.go") - -func readFile(filename string) []byte { - data, err := ioutil.ReadFile(filename) +func BenchmarkParse(b *testing.B) { + src, err := ioutil.ReadFile("parser.go") if err != nil { - panic(err) + b.Fatal(err) } - return data -} - -func BenchmarkParse(b *testing.B) { + b.ResetTimer() b.SetBytes(int64(len(src))) for i := 0; i < b.N; i++ { if _, err := ParseFile(token.NewFileSet(), "", src, ParseComments); err != nil { Index: libgo/go/net/http/serve_test.go =================================================================== --- libgo/go/net/http/serve_test.go (revision 244456) +++ libgo/go/net/http/serve_test.go (working copy) @@ -5173,3 +5173,142 @@ func TestServerDuplicateBackgroundRead(t } wg.Wait() } + +// Test that the bufio.Reader returned by Hijack includes any buffered +// byte (from the Server's backgroundRead) in its buffer. We want the +// Handler code to be able to tell that a byte is available via +// bufio.Reader.Buffered(), without resorting to Reading it +// (potentially blocking) to get at it. +func TestServerHijackGetsBackgroundByte(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping test; see https://golang.org/issue/18657") + } + setParallel(t) + defer afterTest(t) + done := make(chan struct{}) + inHandler := make(chan bool, 1) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + defer close(done) + + // Tell the client to send more data after the GET request. + inHandler <- true + + // Wait until the HTTP server sees the extra data + // after the GET request. The HTTP server fires the + // close notifier here, assuming it's a pipelined + // request, as documented. + select { + case <-w.(CloseNotifier).CloseNotify(): + case <-time.After(5 * time.Second): + t.Error("timeout") + return + } + + conn, buf, err := w.(Hijacker).Hijack() + if err != nil { + t.Error(err) + return + } + defer conn.Close() + n := buf.Reader.Buffered() + if n != 1 { + t.Errorf("buffered data = %d; want 1", n) + } + peek, err := buf.Reader.Peek(3) + if string(peek) != "foo" || err != nil { + t.Errorf("Peek = %q, %v; want foo, nil", peek, err) + } + })) + defer ts.Close() + + cn, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer cn.Close() + if _, err := cn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil { + t.Fatal(err) + } + <-inHandler + if _, err := cn.Write([]byte("foo")); err != nil { + t.Fatal(err) + } + + if err := cn.(*net.TCPConn).CloseWrite(); err != nil { + t.Fatal(err) + } + select { + case <-done: + case <-time.After(2 * time.Second): + t.Error("timeout") + } +} + +// Like TestServerHijackGetsBackgroundByte above but sending a +// immediate 1MB of data to the server to fill up the server's 4KB +// buffer. +func TestServerHijackGetsBackgroundByte_big(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping test; see https://golang.org/issue/18657") + } + setParallel(t) + defer afterTest(t) + done := make(chan struct{}) + const size = 8 << 10 + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + defer close(done) + + // Wait until the HTTP server sees the extra data + // after the GET request. The HTTP server fires the + // close notifier here, assuming it's a pipelined + // request, as documented. + select { + case <-w.(CloseNotifier).CloseNotify(): + case <-time.After(5 * time.Second): + t.Error("timeout") + return + } + + conn, buf, err := w.(Hijacker).Hijack() + if err != nil { + t.Error(err) + return + } + defer conn.Close() + slurp, err := ioutil.ReadAll(buf.Reader) + if err != nil { + t.Error("Copy: %v", err) + } + allX := true + for _, v := range slurp { + if v != 'x' { + allX = false + } + } + if len(slurp) != size { + t.Errorf("read %d; want %d", len(slurp), size) + } else if !allX { + t.Errorf("read %q; want %d 'x'", slurp, size) + } + })) + defer ts.Close() + + cn, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer cn.Close() + if _, err := fmt.Fprintf(cn, "GET / HTTP/1.1\r\nHost: e.com\r\n\r\n%s", + strings.Repeat("x", size)); err != nil { + t.Fatal(err) + } + if err := cn.(*net.TCPConn).CloseWrite(); err != nil { + t.Fatal(err) + } + + select { + case <-done: + case <-time.After(2 * time.Second): + t.Error("timeout") + } +} Index: libgo/go/net/http/server.go =================================================================== --- libgo/go/net/http/server.go (revision 244456) +++ libgo/go/net/http/server.go (working copy) @@ -164,7 +164,7 @@ type Flusher interface { // should always test for this ability at runtime. type Hijacker interface { // Hijack lets the caller take over the connection. - // After a call to Hijack(), the HTTP server library + // After a call to Hijack the HTTP server library // will not do anything else with the connection. // // It becomes the caller's responsibility to manage @@ -174,6 +174,9 @@ type Hijacker interface { // already set, depending on the configuration of the // Server. It is the caller's responsibility to set // or clear those deadlines as needed. + // + // The returned bufio.Reader may contain unprocessed buffered + // data from the client. Hijack() (net.Conn, *bufio.ReadWriter, error) } @@ -293,6 +296,11 @@ func (c *conn) hijackLocked() (rwc net.C rwc.SetDeadline(time.Time{}) buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc)) + if c.r.hasByte { + if _, err := c.bufr.Peek(c.bufr.Buffered() + 1); err != nil { + return nil, nil, fmt.Errorf("unexpected Peek failure reading buffered byte: %v", err) + } + } c.setState(rwc, StateHijacked) return } Index: libgo/go/net/http/transport_test.go =================================================================== --- libgo/go/net/http/transport_test.go (revision 244456) +++ libgo/go/net/http/transport_test.go (working copy) @@ -36,6 +36,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "testing" "time" ) @@ -2545,6 +2546,13 @@ type closerFunc func() error func (f closerFunc) Close() error { return f() } +type writerFuncConn struct { + net.Conn + write func(p []byte) (n int, err error) +} + +func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) } + // Issue 4677. If we try to reuse a connection that the server is in the // process of closing, we may end up successfully writing out our request (or a // portion of our request) only to find a connection error when we try to read @@ -2557,66 +2565,78 @@ func (f closerFunc) Close() error { retu func TestRetryIdempotentRequestsOnError(t *testing.T) { defer afterTest(t) + var ( + mu sync.Mutex + logbuf bytes.Buffer + ) + logf := func(format string, args ...interface{}) { + mu.Lock() + defer mu.Unlock() + fmt.Fprintf(&logbuf, format, args...) + logbuf.WriteByte('\n') + } + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + logf("Handler") + w.Header().Set("X-Status", "ok") })) defer ts.Close() - tr := &Transport{} + var writeNumAtomic int32 + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + logf("Dial") + c, err := net.Dial(network, ts.Listener.Addr().String()) + if err != nil { + logf("Dial error: %v", err) + return nil, err + } + return &writerFuncConn{ + Conn: c, + write: func(p []byte) (n int, err error) { + if atomic.AddInt32(&writeNumAtomic, 1) == 2 { + logf("intentional write failure") + return 0, errors.New("second write fails") + } + logf("Write(%q)", p) + return c.Write(p) + }, + }, nil + }, + } + defer tr.CloseIdleConnections() c := &Client{Transport: tr} - const N = 2 - retryc := make(chan struct{}, N) SetRoundTripRetried(func() { - retryc <- struct{}{} + logf("Retried.") }) defer SetRoundTripRetried(nil) - for n := 0; n < 100; n++ { - // open 2 conns - errc := make(chan error, N) - for i := 0; i < N; i++ { - // start goroutines, send on errc - go func() { - res, err := c.Get(ts.URL) - if err == nil { - res.Body.Close() - } - errc <- err - }() - } - for i := 0; i < N; i++ { - if err := <-errc; err != nil { - t.Fatal(err) - } - } - - ts.CloseClientConnections() - for i := 0; i < N; i++ { - go func() { - res, err := c.Get(ts.URL) - if err == nil { - res.Body.Close() - } - errc <- err - }() + for i := 0; i < 3; i++ { + res, err := c.Get("http://fake.golang/") + if err != nil { + t.Fatalf("i=%d: Get = %v", i, err) } + res.Body.Close() + } - for i := 0; i < N; i++ { - if err := <-errc; err != nil { - t.Fatal(err) - } - } - for i := 0; i < N; i++ { - select { - case <-retryc: - // we triggered a retry, test was successful - t.Logf("finished after %d runs\n", n) - return - default: - } - } + mu.Lock() + got := logbuf.String() + mu.Unlock() + const want = `Dial +Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n") +Handler +intentional write failure +Retried. +Dial +Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n") +Handler +Write("GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n") +Handler +` + if got != want { + t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want) } - t.Fatal("did not trigger any retries") } // Issue 6981 Index: libgo/go/os/os_test.go =================================================================== --- libgo/go/os/os_test.go (revision 244456) +++ libgo/go/os/os_test.go (working copy) @@ -52,12 +52,15 @@ var sysdir = func() *sysDir { case "darwin": switch runtime.GOARCH { case "arm", "arm64": + /// At this point the test harness has not had a chance + // to move us into the ./src/os directory, so the + // current working directory is the root of the app. wd, err := syscall.Getwd() if err != nil { wd = err.Error() } return &sysDir{ - filepath.Join(wd, "..", ".."), + wd, []string{ "ResourceRules.plist", "Info.plist", Index: libgo/go/reflect/all_test.go =================================================================== --- libgo/go/reflect/all_test.go (revision 244456) +++ libgo/go/reflect/all_test.go (working copy) @@ -26,6 +26,8 @@ import ( "unsafe" ) +var sink interface{} + func TestBool(t *testing.T) { v := ValueOf(true) if v.Bool() != true { @@ -5348,6 +5350,72 @@ func TestCallGC(t *testing.T) { f2("four", "five5", "six666", "seven77", "eight888") } +// Issue 18635 (function version). +func TestKeepFuncLive(t *testing.T) { + // Test that we keep makeFuncImpl live as long as it is + // referenced on the stack. + typ := TypeOf(func(i int) {}) + var f, g func(in []Value) []Value + f = func(in []Value) []Value { + clobber() + i := int(in[0].Int()) + if i > 0 { + // We can't use Value.Call here because + // runtime.call* will keep the makeFuncImpl + // alive. However, by converting it to an + // interface value and calling that, + // reflect.callReflect is the only thing that + // can keep the makeFuncImpl live. + // + // Alternate between f and g so that if we do + // reuse the memory prematurely it's more + // likely to get obviously corrupted. + MakeFunc(typ, g).Interface().(func(i int))(i - 1) + } + return nil + } + g = func(in []Value) []Value { + clobber() + i := int(in[0].Int()) + MakeFunc(typ, f).Interface().(func(i int))(i) + return nil + } + MakeFunc(typ, f).Call([]Value{ValueOf(10)}) +} + +// Issue 18635 (method version). +type KeepMethodLive struct{} + +func (k KeepMethodLive) Method1(i int) { + clobber() + if i > 0 { + ValueOf(k).MethodByName("Method2").Interface().(func(i int))(i - 1) + } +} + +func (k KeepMethodLive) Method2(i int) { + clobber() + ValueOf(k).MethodByName("Method1").Interface().(func(i int))(i) +} + +func TestKeepMethodLive(t *testing.T) { + // Test that we keep methodValue live as long as it is + // referenced on the stack. + KeepMethodLive{}.Method1(10) +} + +// clobber tries to clobber unreachable memory. +func clobber() { + runtime.GC() + for i := 1; i < 32; i++ { + for j := 0; j < 10; j++ { + obj := make([]*byte, i) + sink = obj + } + } + runtime.GC() +} + type funcLayoutTest struct { rcvr, t Type size, argsize, retOffset uintptr Index: libgo/go/reflect/type.go =================================================================== --- libgo/go/reflect/type.go (revision 244456) +++ libgo/go/reflect/type.go (working copy) @@ -1677,7 +1677,7 @@ func FuncOf(in, out []Type, variadic boo *ft = *prototype // Build a hash and minimally populate ft. - var hash uint32 = 8 + var hash uint32 var fin, fout []*rtype shift := uint(1) for _, in := range in { @@ -1697,6 +1697,7 @@ func FuncOf(in, out []Type, variadic boo hash++ } hash <<= 4 + hash += 8 ft.hash = hash ft.in = fin ft.out = fout Index: libgo/go/testing/benchmark.go =================================================================== --- libgo/go/testing/benchmark.go (revision 244456) +++ libgo/go/testing/benchmark.go (working copy) @@ -219,7 +219,7 @@ func (b *B) run1() bool { } // Only print the output if we know we are not going to proceed. // Otherwise it is printed in processBench. - if b.hasSub || b.finished { + if atomic.LoadInt32(&b.hasSub) != 0 || b.finished { tag := "BENCH" if b.skipped { tag = "SKIP" @@ -460,10 +460,13 @@ func (ctx *benchContext) processBench(b // // A subbenchmark is like any other benchmark. A benchmark that calls Run at // least once will not be measured itself and will be called once with N=1. +// +// Run may be called simultaneously from multiple goroutines, but all such +// calls must happen before the outer benchmark function for b returns. func (b *B) Run(name string, f func(b *B)) bool { // Since b has subbenchmarks, we will no longer run it as a benchmark itself. // Release the lock and acquire it on exit to ensure locks stay paired. - b.hasSub = true + atomic.StoreInt32(&b.hasSub, 1) benchmarkLock.Unlock() defer benchmarkLock.Lock() Index: libgo/go/testing/sub_test.go =================================================================== --- libgo/go/testing/sub_test.go (revision 244456) +++ libgo/go/testing/sub_test.go (working copy) @@ -6,6 +6,7 @@ package testing import ( "bytes" + "fmt" "regexp" "strings" "sync/atomic" @@ -515,3 +516,19 @@ func TestBenchmarkOutput(t *T) { Benchmark(func(b *B) { b.Error("do not print this output") }) Benchmark(func(b *B) {}) } + +func TestParallelSub(t *T) { + c := make(chan int) + block := make(chan int) + for i := 0; i < 10; i++ { + go func(i int) { + <-block + t.Run(fmt.Sprint(i), func(t *T) {}) + c <- 1 + }(i) + } + close(block) + for i := 0; i < 10; i++ { + <-c + } +} Index: libgo/go/testing/testing.go =================================================================== --- libgo/go/testing/testing.go (revision 244456) +++ libgo/go/testing/testing.go (working copy) @@ -216,6 +216,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" ) @@ -267,8 +268,8 @@ type common struct { skipped bool // Test of benchmark has been skipped. finished bool // Test function has completed. done bool // Test is finished and all subtests have completed. - hasSub bool - raceErrors int // number of races detected during test + hasSub int32 // written atomically + raceErrors int // number of races detected during test parent *common level int // Nesting depth of test or benchmark. @@ -645,7 +646,7 @@ func tRunner(t *T, fn func(t *T)) { // Do not lock t.done to allow race detector to detect race in case // the user does not appropriately synchronizes a goroutine. t.done = true - if t.parent != nil && !t.hasSub { + if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 { t.setRan() } t.signal <- true @@ -659,8 +660,11 @@ func tRunner(t *T, fn func(t *T)) { // Run runs f as a subtest of t called name. It reports whether f succeeded. // Run will block until all its parallel subtests have completed. +// +// Run may be called simultaneously from multiple goroutines, but all such +// calls must happen before the outer test function for t returns. func (t *T) Run(name string, f func(t *T)) bool { - t.hasSub = true + atomic.StoreInt32(&t.hasSub, 1) testName, ok := t.context.match.fullName(&t.common, name) if !ok { return true Index: libgo/merge.sh =================================================================== --- libgo/merge.sh (revision 244456) +++ libgo/merge.sh (working copy) @@ -147,7 +147,7 @@ done (cd ${NEWDIR}/src && find . -name testdata -print) | while read d; do skip=false - case "$f" in + case "$d" in ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/internal/browser/*) ;; ./cmd/*)