From: Ian Lance Taylor Date: Fri, 17 Feb 2017 15:43:39 +0000 (+0000) Subject: libgo: update to final Go 1.8 release X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=00b2a30fd4df92fe5ea879295d65c55bf1725fcb;p=gcc.git libgo: update to final Go 1.8 release Along with the update this fixes a problem that was always present but only showed up with the new reflect test. When a program used a **unsafe.Pointer and stored the value in an interface type, the generated type descriptor pointed to the GC data for *unsafe.Pointer. It did that by name, but we were not generating a variable with the right name. Reviewed-on: https://go-review.googlesource.com/37144 From-SVN: r245535 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 0f5bec0cc6e..9cf7ec34f4a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -c3935e1f20ad5b1d4c41150f11fb266913c04df7 +893f0e4a707c6f10eb14842b18954486042f0fb3 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/MERGE b/libgo/MERGE index fa155a238d6..16f346a2b8e 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -2a5f65a98ca483aad2dd74dc2636a7baecc59cf2 +cd6b6202dd1559b3ac63179b45f1833fcfbe7eca The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/VERSION b/libgo/VERSION index 8b33af3b6b0..436edd93930 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.8rc3 +go1.8 diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index e93fd6ebed7..3d5dd2b3972 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -17,7 +17,7 @@ // clean remove object files // doc show documentation for package or symbol // env print Go environment information -// bug print information for bug reports +// bug start a bug report // fix run go tool fix on packages // fmt run gofmt on package sources // generate generate Go files by processing source @@ -324,15 +324,14 @@ // each named variable on its own line. // // -// Print information for bug reports +// Start a bug report // // Usage: // // go bug // -// 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. // // // Run go tool fix on packages diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go index 1d7677c615c..6fb4235068e 100644 --- a/libgo/go/cmd/go/get.go +++ b/libgo/go/cmd/go/get.go @@ -428,7 +428,7 @@ func downloadPackage(p *Package) error { return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'") } // Guard against people setting GOPATH=$GOROOT. - if list[0] == goroot { + if filepath.Clean(list[0]) == filepath.Clean(goroot) { return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") } if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go index f26c3660e4b..56de65ce55a 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -1683,173 +1683,111 @@ func homeEnvName() string { } } -// Test go env missing GOPATH shows default. -func TestMissingGOPATHEnvShowsDefault(t *testing.T) { +func TestDefaultGOPATH(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.parallel() - tg.setenv("GOPATH", "") - tg.run("env", "GOPATH") + tg.tempDir("home/go") + tg.setenv(homeEnvName(), tg.path("home")) - want := filepath.Join(os.Getenv(homeEnvName()), "go") - got := strings.TrimSpace(tg.getStdout()) - if got != want { - t.Errorf("got %q; want %q", got, want) - } -} - -// Test go get missing GOPATH causes go get to warn if directory doesn't exist. -func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) { - testenv.MustHaveExternalNetwork(t) - - if _, err := exec.LookPath("git"); err != nil { - t.Skip("skipping because git binary not found") - } - - tg := testgo(t) - defer tg.cleanup() - - // setenv variables for test and defer deleting temporary home directory. - tg.setenv("GOPATH", "") - tmp, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("could not create tmp home: %v", err) - } - defer os.RemoveAll(tmp) - tg.setenv(homeEnvName(), tmp) + tg.run("env", "GOPATH") + tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go") - tg.run("get", "-v", "github.com/golang/example/hello") + tg.setenv("GOROOT", tg.path("home/go")) + tg.run("env", "GOPATH") + tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go") - want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go")) - got := strings.TrimSpace(tg.getStderr()) - if !strings.Contains(got, want) { - t.Errorf("got %q; want %q", got, want) - } + tg.setenv("GOROOT", tg.path("home/go")+"/") + tg.run("env", "GOPATH") + tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/") } -// Test go get missing GOPATH causes no warning if directory exists. -func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) { +func TestDefaultGOPATHGet(t *testing.T) { testenv.MustHaveExternalNetwork(t) - if _, err := exec.LookPath("git"); err != nil { - t.Skip("skipping because git binary not found") - } - tg := testgo(t) defer tg.cleanup() - - // setenv variables for test and defer resetting them. tg.setenv("GOPATH", "") - tmp, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("could not create tmp home: %v", err) - } - defer os.RemoveAll(tmp) - if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil { - t.Fatalf("could not create $HOME/go: %v", err) - } + tg.tempDir("home") + tg.setenv(homeEnvName(), tg.path("home")) - tg.setenv(homeEnvName(), tmp) + // warn for creating directory + tg.run("get", "-v", "github.com/golang/example/hello") + tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH") + // no warning if directory already exists + tg.must(os.RemoveAll(tg.path("home/go"))) + tg.tempDir("home/go") tg.run("get", "github.com/golang/example/hello") + tg.grepStderrNot(".", "expected no output on standard error") - got := strings.TrimSpace(tg.getStderr()) - if got != "" { - t.Errorf("got %q; wants empty", got) - } -} - -// Test go get missing GOPATH fails if pointed file is not a directory. -func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) { - testenv.MustHaveExternalNetwork(t) - - tg := testgo(t) - defer tg.cleanup() - - // setenv variables for test and defer resetting them. - tg.setenv("GOPATH", "") - tmp, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("could not create tmp home: %v", err) - } - defer os.RemoveAll(tmp) - - path := filepath.Join(tmp, "go") - if err := ioutil.WriteFile(path, nil, 0777); err != nil { - t.Fatalf("could not create GOPATH at %s: %v", path, err) - } - tg.setenv(homeEnvName(), tmp) - - const pkg = "github.com/golang/example/hello" - tg.runFail("get", pkg) - - msg := "not a directory" - if runtime.GOOS == "windows" { - msg = "The system cannot find the path specified." - } - want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg) - got := strings.TrimSpace(tg.getStderr()) - if got != want { - t.Errorf("got %q; wants %q", got, want) - } + // error if $HOME/go is a file + tg.must(os.RemoveAll(tg.path("home/go"))) + tg.tempFile("home/go", "") + tg.runFail("get", "github.com/golang/example/hello") + tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file") } -// Test go install of missing package when missing GOPATH fails and shows default GOPATH. -func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) { +func TestDefaultGOPATHPrintedSearchList(t *testing.T) { tg := testgo(t) defer tg.cleanup() - - // setenv variables for test and defer resetting them. tg.setenv("GOPATH", "") - tmp, err := ioutil.TempDir("", "") - if err != nil { - t.Fatalf("could not create tmp home: %v", err) - } - defer os.RemoveAll(tmp) - if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil { - t.Fatalf("could not create $HOME/go: %v", err) - } - tg.setenv(homeEnvName(), tmp) - - const pkg = "github.com/golang/example/hello" - tg.runFail("install", pkg) - - pkgPath := filepath.Join(strings.Split(pkg, "/")...) - want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) + - fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) + - fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath)) + tg.tempDir("home") + tg.setenv(homeEnvName(), tg.path("home")) - got := strings.TrimSpace(tg.getStderr()) - if got != want { - t.Errorf("got %q; wants %q", got, want) - } + tg.runFail("install", "github.com/golang/example/hello") + tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH") } // Issue 4186. go get cannot be used to download packages to $GOROOT. // Test that without GOPATH set, go get should fail. -func TestWithoutGOPATHGoGetFails(t *testing.T) { +func TestGoGetIntoGOROOT(t *testing.T) { testenv.MustHaveExternalNetwork(t) tg := testgo(t) defer tg.cleanup() tg.parallel() tg.tempDir("src") - tg.setenv("GOPATH", "") + + // Fails because GOROOT=GOPATH + tg.setenv("GOPATH", tg.path(".")) tg.setenv("GOROOT", tg.path(".")) - tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch") -} + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT") + tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT") -// Test that with GOPATH=$GOROOT, go get should fail. -func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) { - testenv.MustHaveExternalNetwork(t) + // Fails because GOROOT=GOPATH after cleaning. + tg.setenv("GOPATH", tg.path(".")+"/") + tg.setenv("GOROOT", tg.path(".")) + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT") + tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT") - tg := testgo(t) - defer tg.cleanup() - tg.parallel() - tg.tempDir("src") tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GOROOT", tg.path(".")) - tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch") + tg.setenv("GOROOT", tg.path(".")+"/") + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT") + tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT") + + // Fails because GOROOT=$HOME/go so default GOPATH unset. + tg.tempDir("home/go") + tg.setenv(homeEnvName(), tg.path("home")) + tg.setenv("GOPATH", "") + tg.setenv("GOROOT", tg.path("home/go")) + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set") + + tg.setenv(homeEnvName(), tg.path("home")+"/") + tg.setenv("GOPATH", "") + tg.setenv("GOROOT", tg.path("home/go")) + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set") + + tg.setenv(homeEnvName(), tg.path("home")) + tg.setenv("GOPATH", "") + tg.setenv("GOROOT", tg.path("home/go")+"/") + tg.runFail("get", "-d", "github.com/golang/example/hello") + tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set") } func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { @@ -3744,6 +3682,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) { tg.grepBoth(okPattern, "go test did not say ok") } +// Issue 18845 +func TestBenchTimeout(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go") +} + func TestLinkXImportPathEscape(t *testing.T) { // golang.org/issue/16710 tg := testgo(t) diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go index 07fc4e2a905..d80ff2da5fe 100644 --- a/libgo/go/cmd/go/main.go +++ b/libgo/go/cmd/go/main.go @@ -136,7 +136,7 @@ func main() { // Diagnose common mistake: GOPATH==GOROOT. // This setting is equivalent to not setting GOPATH at all, // which is not what most people want when they do it. - if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() { + if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) { fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) } else { for _, p := range filepath.SplitList(gopath) { diff --git a/libgo/go/crypto/x509/root_linux.go b/libgo/go/crypto/x509/root_linux.go index 38dd72d3ed6..aa1785e4c63 100644 --- a/libgo/go/crypto/x509/root_linux.go +++ b/libgo/go/crypto/x509/root_linux.go @@ -7,8 +7,8 @@ package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. - "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 "/etc/ssl/ca-bundle.pem", // OpenSUSE "/etc/pki/tls/cacert.pem", // OpenELEC + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 } diff --git a/libgo/go/database/sql/ctxutil.go b/libgo/go/database/sql/ctxutil.go index 1071446227f..bd652b54625 100644 --- a/libgo/go/database/sql/ctxutil.go +++ b/libgo/go/database/sql/ctxutil.go @@ -35,15 +35,12 @@ func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvda return nil, err } - resi, err := execer.Exec(query, dargs) - if err == nil { - select { - default: - case <-ctx.Done(): - return resi, ctx.Err() - } + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() } - return resi, err + return execer.Exec(query, dargs) } func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) { @@ -56,16 +53,12 @@ func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, n return nil, err } - rowsi, err := queryer.Query(query, dargs) - if err == nil { - select { - default: - case <-ctx.Done(): - rowsi.Close() - return nil, ctx.Err() - } + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() } - return rowsi, err + return queryer.Query(query, dargs) } func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Result, error) { @@ -77,15 +70,12 @@ func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.Nam return nil, err } - resi, err := si.Exec(dargs) - if err == nil { - select { - default: - case <-ctx.Done(): - return resi, ctx.Err() - } + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() } - return resi, err + return si.Exec(dargs) } func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Rows, error) { @@ -97,16 +87,12 @@ func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.Na return nil, err } - rowsi, err := si.Query(dargs) - if err == nil { - select { - default: - case <-ctx.Done(): - rowsi.Close() - return nil, ctx.Err() - } + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() } - return rowsi, err + return si.Query(dargs) } var errLevelNotSupported = errors.New("sql: selected isolation level is not supported") diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go index feb91223a9e..c016681fca1 100644 --- a/libgo/go/database/sql/sql.go +++ b/libgo/go/database/sql/sql.go @@ -305,8 +305,9 @@ type DB struct { mu sync.Mutex // protects following fields freeConn []*driverConn - connRequests []chan connRequest - numOpen int // number of opened and pending open connections + connRequests map[uint64]chan connRequest + nextRequest uint64 // Next key to use in connRequests. + numOpen int // number of opened and pending open connections // Used to signal the need for new connections // a goroutine running connectionOpener() reads on this chan and // maybeOpenNewConnections sends on the chan (one send per needed connection) @@ -572,10 +573,11 @@ func Open(driverName, dataSourceName string) (*DB, error) { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) } db := &DB{ - driver: driveri, - dsn: dataSourceName, - openerCh: make(chan struct{}, connectionRequestQueueSize), - lastPut: make(map[*driverConn]string), + driver: driveri, + dsn: dataSourceName, + openerCh: make(chan struct{}, connectionRequestQueueSize), + lastPut: make(map[*driverConn]string), + connRequests: make(map[uint64]chan connRequest), } go db.connectionOpener() return db, nil @@ -881,6 +883,14 @@ type connRequest struct { var errDBClosed = errors.New("sql: database is closed") +// nextRequestKeyLocked returns the next connection request key. +// It is assumed that nextRequest will not overflow. +func (db *DB) nextRequestKeyLocked() uint64 { + next := db.nextRequest + db.nextRequest++ + return next +} + // conn returns a newly-opened or cached *driverConn. func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) { db.mu.Lock() @@ -918,12 +928,25 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn // Make the connRequest channel. It's buffered so that the // connectionOpener doesn't block while waiting for the req to be read. req := make(chan connRequest, 1) - db.connRequests = append(db.connRequests, req) + reqKey := db.nextRequestKeyLocked() + db.connRequests[reqKey] = req db.mu.Unlock() // Timeout the connection request with the context. select { case <-ctx.Done(): + // Remove the connection request and ensure no value has been sent + // on it after removing. + db.mu.Lock() + delete(db.connRequests, reqKey) + db.mu.Unlock() + select { + default: + case ret, ok := <-req: + if ok { + db.putConn(ret.conn, ret.err) + } + } return nil, ctx.Err() case ret, ok := <-req: if !ok { @@ -1044,12 +1067,12 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool { return false } if c := len(db.connRequests); c > 0 { - req := db.connRequests[0] - // This copy is O(n) but in practice faster than a linked list. - // TODO: consider compacting it down less often and - // moving the base instead? - copy(db.connRequests, db.connRequests[1:]) - db.connRequests = db.connRequests[:c-1] + var req chan connRequest + var reqKey uint64 + for reqKey, req = range db.connRequests { + break + } + delete(db.connRequests, reqKey) // Remove from pending requests. if err == nil { dc.inUse = true } @@ -2071,14 +2094,21 @@ type Rows struct { dc *driverConn // owned; must call releaseConn when closed to release releaseConn func(error) rowsi driver.Rows + cancel func() // called when Rows is closed, may be nil. + closeStmt *driverStmt // if non-nil, statement to Close on close - // closed value is 1 when the Rows is closed. - // Use atomic operations on value when checking value. - closed int32 - cancel func() // called when Rows is closed, may be nil. - lastcols []driver.Value - lasterr error // non-nil only if closed is true - closeStmt *driverStmt // if non-nil, statement to Close on close + // closemu prevents Rows from closing while there + // is an active streaming result. It is held for read during non-close operations + // and exclusively during close. + // + // closemu guards lasterr and closed. + closemu sync.RWMutex + closed bool + lasterr error // non-nil only if closed is true + + // lastcols is only used in Scan, Next, and NextResultSet which are expected + // not not be called concurrently. + lastcols []driver.Value } func (rs *Rows) initContextClose(ctx context.Context) { @@ -2089,7 +2119,7 @@ func (rs *Rows) initContextClose(ctx context.Context) { // awaitDone blocks until the rows are closed or the context canceled. func (rs *Rows) awaitDone(ctx context.Context) { <-ctx.Done() - rs.Close() + rs.close(ctx.Err()) } // Next prepares the next result row for reading with the Scan method. It @@ -2099,8 +2129,19 @@ func (rs *Rows) awaitDone(ctx context.Context) { // // Every call to Scan, even the first one, must be preceded by a call to Next. func (rs *Rows) Next() bool { - if rs.isClosed() { - return false + var doClose, ok bool + withLock(rs.closemu.RLocker(), func() { + doClose, ok = rs.nextLocked() + }) + if doClose { + rs.Close() + } + return ok +} + +func (rs *Rows) nextLocked() (doClose, ok bool) { + if rs.closed { + return false, false } if rs.lastcols == nil { rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns())) @@ -2109,23 +2150,21 @@ func (rs *Rows) Next() bool { if rs.lasterr != nil { // Close the connection if there is a driver error. if rs.lasterr != io.EOF { - rs.Close() - return false + return true, false } nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet) if !ok { - rs.Close() - return false + return true, false } // The driver is at the end of the current result set. // Test to see if there is another result set after the current one. // Only close Rows if there is no further result sets to read. if !nextResultSet.HasNextResultSet() { - rs.Close() + doClose = true } - return false + return doClose, false } - return true + return false, true } // NextResultSet prepares the next result set for reading. It returns true if @@ -2137,18 +2176,28 @@ func (rs *Rows) Next() bool { // scanning. If there are further result sets they may not have rows in the result // set. func (rs *Rows) NextResultSet() bool { - if rs.isClosed() { + var doClose bool + defer func() { + if doClose { + rs.Close() + } + }() + rs.closemu.RLock() + defer rs.closemu.RUnlock() + + if rs.closed { return false } + rs.lastcols = nil nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet) if !ok { - rs.Close() + doClose = true return false } rs.lasterr = nextResultSet.NextResultSet() if rs.lasterr != nil { - rs.Close() + doClose = true return false } return true @@ -2157,6 +2206,8 @@ func (rs *Rows) NextResultSet() bool { // Err returns the error, if any, that was encountered during iteration. // Err may be called after an explicit or implicit Close. func (rs *Rows) Err() error { + rs.closemu.RLock() + defer rs.closemu.RUnlock() if rs.lasterr == io.EOF { return nil } @@ -2167,7 +2218,9 @@ func (rs *Rows) Err() error { // Columns returns an error if the rows are closed, or if the rows // are from QueryRow and there was a deferred error. func (rs *Rows) Columns() ([]string, error) { - if rs.isClosed() { + rs.closemu.RLock() + defer rs.closemu.RUnlock() + if rs.closed { return nil, errors.New("sql: Rows are closed") } if rs.rowsi == nil { @@ -2179,7 +2232,9 @@ func (rs *Rows) Columns() ([]string, error) { // ColumnTypes returns column information such as column type, length, // and nullable. Some information may not be available from some drivers. func (rs *Rows) ColumnTypes() ([]*ColumnType, error) { - if rs.isClosed() { + rs.closemu.RLock() + defer rs.closemu.RUnlock() + if rs.closed { return nil, errors.New("sql: Rows are closed") } if rs.rowsi == nil { @@ -2329,9 +2384,13 @@ func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType { // For scanning into *bool, the source may be true, false, 1, 0, or // string inputs parseable by strconv.ParseBool. func (rs *Rows) Scan(dest ...interface{}) error { - if rs.isClosed() { + rs.closemu.RLock() + if rs.closed { + rs.closemu.RUnlock() return errors.New("sql: Rows are closed") } + rs.closemu.RUnlock() + if rs.lastcols == nil { return errors.New("sql: Scan called without calling Next") } @@ -2351,20 +2410,28 @@ func (rs *Rows) Scan(dest ...interface{}) error { // hook throug a test only mutex. var rowsCloseHook = func() func(*Rows, *error) { return nil } -func (rs *Rows) isClosed() bool { - return atomic.LoadInt32(&rs.closed) != 0 -} - // Close closes the Rows, preventing further enumeration. If Next is called // and returns false and there are no further result sets, // the Rows are closed automatically and it will suffice to check the // result of Err. Close is idempotent and does not affect the result of Err. func (rs *Rows) Close() error { - if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) { + return rs.close(nil) +} + +func (rs *Rows) close(err error) error { + rs.closemu.Lock() + defer rs.closemu.Unlock() + + if rs.closed { return nil } + rs.closed = true + + if rs.lasterr == nil { + rs.lasterr = err + } - err := rs.rowsi.Close() + err = rs.rowsi.Close() if fn := rowsCloseHook(); fn != nil { fn(rs, &err) } diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go index 898df3b455b..450e5f1f8c9 100644 --- a/libgo/go/database/sql/sql_test.go +++ b/libgo/go/database/sql/sql_test.go @@ -153,8 +153,13 @@ func closeDB(t testing.TB, db *DB) { if err != nil { t.Fatalf("error closing DB: %v", err) } - if count := db.numOpenConns(); count != 0 { - t.Fatalf("%d connections still open after closing DB", count) + + var numOpen int + if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool { + numOpen = db.numOpenConns() + return numOpen == 0 + }) { + t.Fatalf("%d connections still open after closing DB", numOpen) } } @@ -276,6 +281,7 @@ func TestQuery(t *testing.T) { } } +// TestQueryContext tests canceling the context while scanning the rows. func TestQueryContext(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -297,7 +303,7 @@ func TestQueryContext(t *testing.T) { for rows.Next() { if index == 2 { cancel() - time.Sleep(10 * time.Millisecond) + waitForRowsClose(t, rows, 5*time.Second) } var r row err = rows.Scan(&r.age, &r.name) @@ -313,9 +319,13 @@ func TestQueryContext(t *testing.T) { got = append(got, r) index++ } - err = rows.Err() - if err != nil { - t.Fatalf("Err: %v", err) + select { + case <-ctx.Done(): + if err := ctx.Err(); err != context.Canceled { + t.Fatalf("context err = %v; want context.Canceled") + } + default: + t.Fatalf("context err = nil; want context.Canceled") } want := []row{ {age: 1, name: "Alice"}, @@ -327,6 +337,7 @@ func TestQueryContext(t *testing.T) { // And verify that the final rows.Next() call, which hit EOF, // also closed the rows connection. + waitForRowsClose(t, rows, 5*time.Second) waitForFree(t, db, 5*time.Second, 1) if prepares := numPrepares(t, db) - prepares0; prepares != 1 { t.Errorf("executed %d Prepare statements; want 1", prepares) @@ -356,12 +367,27 @@ func waitForFree(t *testing.T, db *DB, maxWait time.Duration, want int) { } } +func waitForRowsClose(t *testing.T, rows *Rows, maxWait time.Duration) { + if !waitCondition(maxWait, 5*time.Millisecond, func() bool { + rows.closemu.RLock() + defer rows.closemu.RUnlock() + return rows.closed + }) { + t.Fatal("failed to close rows") + } +} + +// TestQueryContextWait ensures that rows and all internal statements are closed when +// a query context is closed during execution. func TestQueryContextWait(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) prepares0 := numPrepares(t, db) - ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15) + // TODO(kardianos): convert this from using a timeout to using an explicit + // cancel when the query signals that is is "executing" the query. + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond) + defer cancel() // This will trigger the *fakeConn.Prepare method which will take time // performing the query. The ctxDriverPrepare func will check the context @@ -374,10 +400,15 @@ func TestQueryContextWait(t *testing.T) { // Verify closed rows connection after error condition. waitForFree(t, db, 5*time.Second, 1) if prepares := numPrepares(t, db) - prepares0; prepares != 1 { - t.Errorf("executed %d Prepare statements; want 1", prepares) + // TODO(kardianos): if the context timeouts before the db.QueryContext + // executes this check may fail. After adjusting how the context + // is canceled above revert this back to a Fatal error. + t.Logf("executed %d Prepare statements; want 1", prepares) } } +// TestTxContextWait tests the transaction behavior when the tx context is canceled +// during execution of the query. func TestTxContextWait(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -386,6 +417,10 @@ func TestTxContextWait(t *testing.T) { tx, err := db.BeginTx(ctx, nil) if err != nil { + // Guard against the context being canceled before BeginTx completes. + if err == context.DeadlineExceeded { + t.Skip("tx context canceled prior to first use") + } t.Fatal(err) } @@ -398,12 +433,6 @@ func TestTxContextWait(t *testing.T) { } waitForFree(t, db, 5*time.Second, 0) - - // Ensure the dropped connection allows more connections to be made. - // Checked on DB Close. - waitCondition(5*time.Second, 5*time.Millisecond, func() bool { - return db.numOpenConns() == 0 - }) } func TestMultiResultSetQuery(t *testing.T) { @@ -527,6 +556,63 @@ func TestQueryNamedArg(t *testing.T) { } } +func TestPoolExhaustOnCancel(t *testing.T) { + if testing.Short() { + t.Skip("long test") + } + db := newTestDB(t, "people") + defer closeDB(t, db) + + max := 3 + + db.SetMaxOpenConns(max) + + // First saturate the connection pool. + // Then start new requests for a connection that is cancelled after it is requested. + + var saturate, saturateDone sync.WaitGroup + saturate.Add(max) + saturateDone.Add(max) + + for i := 0; i < max; i++ { + go func() { + saturate.Done() + rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|") + if err != nil { + t.Fatalf("Query: %v", err) + } + rows.Close() + saturateDone.Done() + }() + } + + saturate.Wait() + + // Now cancel the request while it is waiting. + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + + for i := 0; i < max; i++ { + ctxReq, cancelReq := context.WithCancel(ctx) + go func() { + time.Sleep(time.Millisecond * 100) + cancelReq() + }() + err := db.PingContext(ctxReq) + if err != context.Canceled { + t.Fatalf("PingContext (Exhaust): %v", err) + } + } + + saturateDone.Wait() + + // Now try to open a normal connection. + err := db.PingContext(ctx) + if err != nil { + t.Fatalf("PingContext (Normal): %v", err) + } +} + func TestByteOwnership(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -2677,7 +2763,6 @@ func TestIssue18429(t *testing.T) { }() } wg.Wait() - time.Sleep(milliWait * 3 * time.Millisecond) } // TestIssue18719 closes the context right before use. The sql.driverConn @@ -2720,14 +2805,8 @@ func TestIssue18719(t *testing.T) { // Do not explicitly rollback. The rollback will happen from the // canceled context. - // Wait for connections to return to pool. - var numOpen int - if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool { - numOpen = db.numOpenConns() - return numOpen == 0 - }) { - t.Fatalf("open conns after hitting EOF = %d; want 0", numOpen) - } + cancel() + waitForRowsClose(t, rows, 5*time.Second) } func TestConcurrency(t *testing.T) { diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 1176f5d717d..4c6ba8c1a5a 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -775,6 +775,20 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, [] var ddBytes = []byte("--") +// indirect drills into interfaces and pointers, returning the pointed-at value. +// If it encounters a nil interface or pointer, indirect returns that nil value. +// This can turn into an infinite loop given a cyclic chain, +// but it matches the Go 1 behavior. +func indirect(vf reflect.Value) reflect.Value { + for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr { + if vf.IsNil() { + return vf + } + vf = vf.Elem() + } + return vf +} + func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { s := parentStack{p: p} for i := range tinfo.fields { @@ -816,17 +830,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { continue } } - // Drill into interfaces and pointers. - // This can turn into an infinite loop given a cyclic chain, - // but it matches the Go 1 behavior. - for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr { - if vf.IsNil() { - return nil - } - vf = vf.Elem() - } var scratch [64]byte + vf = indirect(vf) switch vf.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil { @@ -861,6 +867,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { if err := s.trim(finfo.parents); err != nil { return err } + vf = indirect(vf) k := vf.Kind() if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) @@ -901,6 +908,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { continue case fInnerXml: + vf = indirect(vf) iface := vf.Interface() switch raw := iface.(type) { case []byte: diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index d79b99a1e0b..5ec7ececa4d 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -386,6 +386,140 @@ func ifaceptr(x interface{}) interface{} { return &x } +func stringptr(x string) *string { + return &x +} + +type T1 struct{} +type T2 struct{} +type T3 struct{} + +type IndirComment struct { + T1 T1 + Comment *string `xml:",comment"` + T2 T2 +} + +type DirectComment struct { + T1 T1 + Comment string `xml:",comment"` + T2 T2 +} + +type IfaceComment struct { + T1 T1 + Comment interface{} `xml:",comment"` + T2 T2 +} + +type IndirChardata struct { + T1 T1 + Chardata *string `xml:",chardata"` + T2 T2 +} + +type DirectChardata struct { + T1 T1 + Chardata string `xml:",chardata"` + T2 T2 +} + +type IfaceChardata struct { + T1 T1 + Chardata interface{} `xml:",chardata"` + T2 T2 +} + +type IndirCDATA struct { + T1 T1 + CDATA *string `xml:",cdata"` + T2 T2 +} + +type DirectCDATA struct { + T1 T1 + CDATA string `xml:",cdata"` + T2 T2 +} + +type IfaceCDATA struct { + T1 T1 + CDATA interface{} `xml:",cdata"` + T2 T2 +} + +type IndirInnerXML struct { + T1 T1 + InnerXML *string `xml:",innerxml"` + T2 T2 +} + +type DirectInnerXML struct { + T1 T1 + InnerXML string `xml:",innerxml"` + T2 T2 +} + +type IfaceInnerXML struct { + T1 T1 + InnerXML interface{} `xml:",innerxml"` + T2 T2 +} + +type IndirElement struct { + T1 T1 + Element *string + T2 T2 +} + +type DirectElement struct { + T1 T1 + Element string + T2 T2 +} + +type IfaceElement struct { + T1 T1 + Element interface{} + T2 T2 +} + +type IndirOmitEmpty struct { + T1 T1 + OmitEmpty *string `xml:",omitempty"` + T2 T2 +} + +type DirectOmitEmpty struct { + T1 T1 + OmitEmpty string `xml:",omitempty"` + T2 T2 +} + +type IfaceOmitEmpty struct { + T1 T1 + OmitEmpty interface{} `xml:",omitempty"` + T2 T2 +} + +type IndirAny struct { + T1 T1 + Any *string `xml:",any"` + T2 T2 +} + +type DirectAny struct { + T1 T1 + Any string `xml:",any"` + T2 T2 +} + +type IfaceAny struct { + T1 T1 + Any interface{} `xml:",any"` + T2 T2 +} + var ( nameAttr = "Sarah" ageAttr = uint(12) @@ -398,10 +532,12 @@ var ( // please try to make them two-way as well to ensure that // marshaling and unmarshaling are as symmetrical as feasible. var marshalTests = []struct { - Value interface{} - ExpectXML string - MarshalOnly bool - UnmarshalOnly bool + Value interface{} + ExpectXML string + MarshalOnly bool + MarshalError string + UnmarshalOnly bool + UnmarshalError string }{ // Test nil marshals to nothing {Value: nil, ExpectXML: ``, MarshalOnly: true}, @@ -1133,6 +1269,382 @@ var marshalTests = []struct { ExpectXML: ``, Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"}, }, + // Test pointer indirection in various kinds of fields. + // https://golang.org/issue/19063 + { + ExpectXML: ``, + Value: &IndirComment{Comment: stringptr("hi")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirComment{Comment: stringptr("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirComment{Comment: nil}, + MarshalError: "xml: bad type for comment field of xml.IndirComment", + }, + { + ExpectXML: ``, + Value: &IndirComment{Comment: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceComment{Comment: "hi"}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceComment{Comment: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceComment{Comment: nil}, + MarshalError: "xml: bad type for comment field of xml.IfaceComment", + }, + { + ExpectXML: ``, + Value: &IfaceComment{Comment: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectComment{Comment: string("hi")}, + }, + { + ExpectXML: ``, + Value: &DirectComment{Comment: string("")}, + }, + { + ExpectXML: `hi`, + Value: &IndirChardata{Chardata: stringptr("hi")}, + }, + { + ExpectXML: ``, + Value: &IndirChardata{Chardata: stringptr("hi")}, + UnmarshalOnly: true, // marshals without CDATA + }, + { + ExpectXML: ``, + Value: &IndirChardata{Chardata: stringptr("")}, + }, + { + ExpectXML: ``, + Value: &IndirChardata{Chardata: nil}, + MarshalOnly: true, // unmarshal leaves Chardata=stringptr("") + }, + { + ExpectXML: `hi`, + Value: &IfaceChardata{Chardata: string("hi")}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &IfaceChardata{Chardata: string("hi")}, + UnmarshalOnly: true, // marshals without CDATA + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &IfaceChardata{Chardata: string("")}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &IfaceChardata{Chardata: nil}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: `hi`, + Value: &DirectChardata{Chardata: string("hi")}, + }, + { + ExpectXML: ``, + Value: &DirectChardata{Chardata: string("hi")}, + UnmarshalOnly: true, // marshals without CDATA + }, + { + ExpectXML: ``, + Value: &DirectChardata{Chardata: string("")}, + }, + { + ExpectXML: ``, + Value: &IndirCDATA{CDATA: stringptr("hi")}, + }, + { + ExpectXML: `hi`, + Value: &IndirCDATA{CDATA: stringptr("hi")}, + UnmarshalOnly: true, // marshals with CDATA + }, + { + ExpectXML: ``, + Value: &IndirCDATA{CDATA: stringptr("")}, + }, + { + ExpectXML: ``, + Value: &IndirCDATA{CDATA: nil}, + MarshalOnly: true, // unmarshal leaves CDATA=stringptr("") + }, + { + ExpectXML: ``, + Value: &IfaceCDATA{CDATA: string("hi")}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: `hi`, + Value: &IfaceCDATA{CDATA: string("hi")}, + UnmarshalOnly: true, // marshals with CDATA + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &IfaceCDATA{CDATA: string("")}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &IfaceCDATA{CDATA: nil}, + UnmarshalError: "cannot unmarshal into interface {}", + }, + { + ExpectXML: ``, + Value: &DirectCDATA{CDATA: string("hi")}, + }, + { + ExpectXML: `hi`, + Value: &DirectCDATA{CDATA: string("hi")}, + UnmarshalOnly: true, // marshals with CDATA + }, + { + ExpectXML: ``, + Value: &DirectCDATA{CDATA: string("")}, + }, + { + ExpectXML: ``, + Value: &IndirInnerXML{InnerXML: stringptr("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirInnerXML{InnerXML: stringptr("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirInnerXML{InnerXML: nil}, + }, + { + ExpectXML: ``, + Value: &IndirInnerXML{InnerXML: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceInnerXML{InnerXML: ""}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceInnerXML{InnerXML: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceInnerXML{InnerXML: nil}, + }, + { + ExpectXML: ``, + Value: &IfaceInnerXML{InnerXML: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectInnerXML{InnerXML: string("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectInnerXML{InnerXML: string("")}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectInnerXML{InnerXML: string("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectInnerXML{InnerXML: string("")}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &IndirElement{Element: stringptr("hi")}, + }, + { + ExpectXML: ``, + Value: &IndirElement{Element: stringptr("")}, + }, + { + ExpectXML: ``, + Value: &IndirElement{Element: nil}, + }, + { + ExpectXML: `hi`, + Value: &IfaceElement{Element: "hi"}, + MarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &IfaceElement{Element: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceElement{Element: nil}, + }, + { + ExpectXML: ``, + Value: &IfaceElement{Element: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &DirectElement{Element: string("hi")}, + }, + { + ExpectXML: ``, + Value: &DirectElement{Element: string("")}, + }, + { + ExpectXML: `hi`, + Value: &IndirOmitEmpty{OmitEmpty: stringptr("hi")}, + }, + { + // Note: Changed in Go 1.8 to include element (because x.OmitEmpty != nil). + ExpectXML: ``, + Value: &IndirOmitEmpty{OmitEmpty: stringptr("")}, + MarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirOmitEmpty{OmitEmpty: stringptr("")}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirOmitEmpty{OmitEmpty: nil}, + }, + { + ExpectXML: `hi`, + Value: &IfaceOmitEmpty{OmitEmpty: "hi"}, + MarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &IfaceOmitEmpty{OmitEmpty: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceOmitEmpty{OmitEmpty: nil}, + }, + { + ExpectXML: ``, + Value: &IfaceOmitEmpty{OmitEmpty: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &DirectOmitEmpty{OmitEmpty: string("hi")}, + }, + { + ExpectXML: ``, + Value: &DirectOmitEmpty{OmitEmpty: string("")}, + }, + { + ExpectXML: `hi`, + Value: &IndirAny{Any: stringptr("hi")}, + }, + { + ExpectXML: ``, + Value: &IndirAny{Any: stringptr("")}, + }, + { + ExpectXML: ``, + Value: &IndirAny{Any: nil}, + }, + { + ExpectXML: `hi`, + Value: &IfaceAny{Any: "hi"}, + MarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &IfaceAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceAny{Any: nil}, + }, + { + ExpectXML: ``, + Value: &IfaceAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &DirectAny{Any: string("hi")}, + }, + { + ExpectXML: ``, + Value: &DirectAny{Any: string("")}, + }, + { + ExpectXML: `hi`, + Value: &IndirAny{Any: stringptr("hi")}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirAny{Any: stringptr("")}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IndirAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &IfaceAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &IfaceAny{Any: nil}, + UnmarshalOnly: true, + }, + { + ExpectXML: `hi`, + Value: &DirectAny{Any: string("hi")}, + UnmarshalOnly: true, + }, + { + ExpectXML: ``, + Value: &DirectAny{Any: string("")}, + UnmarshalOnly: true, + }, } func TestMarshal(t *testing.T) { @@ -1142,7 +1654,17 @@ func TestMarshal(t *testing.T) { } data, err := Marshal(test.Value) if err != nil { - t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) + if test.MarshalError == "" { + t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) + continue + } + if !strings.Contains(err.Error(), test.MarshalError) { + t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError) + } + continue + } + if test.MarshalError != "" { + t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError) continue } if got, want := string(data), test.ExpectXML; got != want { @@ -1268,8 +1790,16 @@ func TestUnmarshal(t *testing.T) { } if err != nil { - t.Errorf("#%d: unexpected error: %#v", i, err) - } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { + if test.UnmarshalError == "" { + t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err) + continue + } + if !strings.Contains(err.Error(), test.UnmarshalError) { + t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError) + } + continue + } + if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want) } } diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index cb053ebbed2..4e1b29fecd9 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -266,7 +266,7 @@ func defaultGOPATH() string { } if home := os.Getenv(env); home != "" { def := filepath.Join(home, "go") - if def == runtime.GOROOT() { + if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) { // Don't set the default GOPATH to GOROOT, // as that will trigger warnings from the go tool. return "" diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 6b143df00e1..859de7c8670 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -2481,17 +2481,24 @@ func TestNumMethodOnDDD(t *testing.T) { } func TestPtrTo(t *testing.T) { + // This block of code means that the ptrToThis field of the + // reflect data for *unsafe.Pointer is non zero, see + // https://golang.org/issue/19003 + var x unsafe.Pointer + var y = &x + var z = &y + var i int - typ := TypeOf(i) + typ := TypeOf(z) for i = 0; i < 100; i++ { typ = PtrTo(typ) } for i = 0; i < 100; i++ { typ = typ.Elem() } - if typ != TypeOf(i) { - t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i)) + if typ != TypeOf(z) { + t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z)) } } diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 29d89f7176d..03252604556 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -1174,6 +1174,7 @@ func (t *rtype) ptrTo() *rtype { pp := *prototype pp.string = &s + pp.ptrToThis = nil // For the type structures linked into the binary, the // compiler provides a good hash of the string. diff --git a/libgo/go/runtime/testdata/testprogcgo/threadpprof.go b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go index 44afb91d96f..3da82961b9b 100644 --- a/libgo/go/runtime/testdata/testprogcgo/threadpprof.go +++ b/libgo/go/runtime/testdata/testprogcgo/threadpprof.go @@ -61,7 +61,7 @@ static void* cpuHogDriver(void* arg __attribute__ ((unused))) { return 0; } -void runCPUHogThread() { +void runCPUHogThread(void) { pthread_t tid; pthread_create(&tid, 0, cpuHogDriver, 0); } diff --git a/libgo/go/runtime/testdata/testprogcgo/traceback.go b/libgo/go/runtime/testdata/testprogcgo/traceback.go index e8b0a04556a..2a023f66cae 100644 --- a/libgo/go/runtime/testdata/testprogcgo/traceback.go +++ b/libgo/go/runtime/testdata/testprogcgo/traceback.go @@ -15,16 +15,16 @@ package main char *p; -static int f3() { +static int f3(void) { *p = 0; return 0; } -static int f2() { +static int f2(void) { return f3(); } -static int f1() { +static int f1(void) { return f2(); } diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index bbeb95692a1..b002aa0bf10 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -821,6 +821,7 @@ func (m *M) Run() int { haveExamples = len(m.examples) > 0 testRan, testOk := runTests(m.deps.MatchString, m.tests) exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples) + stopAlarm() if !testRan && !exampleRan && *matchBenchmarks == "" { fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") } diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c index cce2e95ac28..3a97ee1d4ad 100644 --- a/libgo/runtime/go-unsafe-pointer.c +++ b/libgo/runtime/go-unsafe-pointer.c @@ -85,6 +85,12 @@ static const String preflection_string = sizeof PREFLECTION - 1, }; +extern const uintptr pointer_unsafe_Pointer_gc[] + __asm__ (GOSYM_PREFIX "__go_td_pN14_unsafe.Pointer$gc"); + +const uintptr pointer_unsafe_Pointer_gc[] __attribute__((aligned(4))) = + {sizeof(void*), GC_APTR, 0, GC_END}; + const struct __go_ptr_type pointer_unsafe_Pointer = { /* __common */ @@ -104,7 +110,7 @@ const struct __go_ptr_type pointer_unsafe_Pointer = /* __equalfn */ &runtime_pointerequal_descriptor, /* __gc */ - unsafe_Pointer_gc, + pointer_unsafe_Pointer_gc, /* __reflection */ &preflection_string, /* __uncommon */