From 74df79ec3e0a1af87e2619fc07533aba58680f0a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 19 Aug 2021 12:29:54 -0700 Subject: [PATCH] libgo: update to final Go 1.17 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/343729 --- gcc/go/gofrontend/MERGE | 2 +- libgo/MERGE | 2 +- libgo/VERSION | 2 +- libgo/go/cmd/go/internal/modload/buildlist.go | 19 +++ libgo/go/cmd/go/internal/modload/init.go | 39 +++---- .../go/testdata/script/mod_tidy_lazy_self.txt | 17 +-- libgo/go/io/fs/fs.go | 2 +- libgo/go/net/http/transport_test.go | 81 ++++++++----- libgo/go/runtime/mfinal.go | 4 + libgo/go/sync/atomic/value.go | 2 +- libgo/go/time/format.go | 6 +- libgo/misc/cgo/testsanitizers/msan_test.go | 1 + .../misc/cgo/testsanitizers/testdata/msan8.go | 109 ++++++++++++++++++ 13 files changed, 218 insertions(+), 68 deletions(-) create mode 100644 libgo/misc/cgo/testsanitizers/testdata/msan8.go diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 950f1797b55..e9f38d449a4 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -77bc32767b61feb6499ca7921e96b356603517dc +b3fad6957a04520013197ea7cab11bec3298d552 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 4286d5c5433..d037d8d06a2 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -72ab3ff68b1ec894fe5599ec82b8849f3baa9d94 +ec5170397c724a8ae440b2bc529f857c86f0e6b1 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 904eb73bd5c..efcff2916b0 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.17rc2 +go1.17 diff --git a/libgo/go/cmd/go/internal/modload/buildlist.go b/libgo/go/cmd/go/internal/modload/buildlist.go index 604a57b4373..bf695673167 100644 --- a/libgo/go/cmd/go/internal/modload/buildlist.go +++ b/libgo/go/cmd/go/internal/modload/buildlist.go @@ -191,6 +191,19 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) { return "", false } +// hasRedundantRoot returns true if the root list contains multiple requirements +// of the same module or a requirement on any version of the main module. +// Redundant requirements should be pruned, but they may influence version +// selection. +func (rs *Requirements) hasRedundantRoot() bool { + for i, m := range rs.rootModules { + if m.Path == Target.Path || (i > 0 && m.Path == rs.rootModules[i-1].Path) { + return true + } + } + return false +} + // Graph returns the graph of module requirements loaded from the current // root modules (as reported by RootModules). // @@ -882,6 +895,12 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen // and (trivially) version. if !rootsUpgraded { + if cfg.BuildMod != "mod" { + // The only changes to the root set (if any) were to remove duplicates. + // The requirements are consistent (if perhaps redundant), so keep the + // original rs to preserve its ModuleGraph. + return rs, nil + } // The root set has converged: every root going into this iteration was // already at its selected version, although we have have removed other // (redundant) roots for the same path. diff --git a/libgo/go/cmd/go/internal/modload/init.go b/libgo/go/cmd/go/internal/modload/init.go index a8cbd9fe16d..45f724d5e36 100644 --- a/libgo/go/cmd/go/internal/modload/init.go +++ b/libgo/go/cmd/go/internal/modload/init.go @@ -449,13 +449,22 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { } setDefaultBuildMod() // possibly enable automatic vendoring - rs = requirementsFromModFile(ctx) - + rs = requirementsFromModFile() if cfg.BuildMod == "vendor" { readVendorList() checkVendorConsistency() rs.initVendor(vendorList) } + if rs.hasRedundantRoot() { + // If any module path appears more than once in the roots, we know that the + // go.mod file needs to be updated even though we have not yet loaded any + // transitive dependencies. + rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) + if err != nil { + base.Fatalf("go: %v", err) + } + } + if index.goVersionV == "" { // TODO(#45551): Do something more principled instead of checking // cfg.CmdName directly here. @@ -530,7 +539,12 @@ func CreateModFile(ctx context.Context, modPath string) { base.Fatalf("go: %v", err) } - commitRequirements(ctx, modFileGoVersion(), requirementsFromModFile(ctx)) + rs := requirementsFromModFile() + rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) + if err != nil { + base.Fatalf("go: %v", err) + } + commitRequirements(ctx, modFileGoVersion(), rs) // Suggest running 'go mod tidy' unless the project is empty. Even if we // imported all the correct requirements above, we're probably missing @@ -641,9 +655,8 @@ func initTarget(m module.Version) { // requirementsFromModFile returns the set of non-excluded requirements from // the global modFile. -func requirementsFromModFile(ctx context.Context) *Requirements { +func requirementsFromModFile() *Requirements { roots := make([]module.Version, 0, len(modFile.Require)) - mPathCount := map[string]int{Target.Path: 1} direct := map[string]bool{} for _, r := range modFile.Require { if index != nil && index.exclude[r.Mod] { @@ -656,28 +669,12 @@ func requirementsFromModFile(ctx context.Context) *Requirements { } roots = append(roots, r.Mod) - mPathCount[r.Mod.Path]++ if !r.Indirect { direct[r.Mod.Path] = true } } module.Sort(roots) rs := newRequirements(modDepthFromGoVersion(modFileGoVersion()), roots, direct) - - // If any module path appears more than once in the roots, we know that the - // go.mod file needs to be updated even though we have not yet loaded any - // transitive dependencies. - for _, n := range mPathCount { - if n > 1 { - var err error - rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) - if err != nil { - base.Fatalf("go: %v", err) - } - break - } - } - return rs } diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt b/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt index ffcea186035..9abbabd2ebe 100644 --- a/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt +++ b/libgo/go/cmd/go/testdata/script/mod_tidy_lazy_self.txt @@ -2,18 +2,13 @@ # 'go mod tidy' should not panic if the main module initially # requires an older version of itself. +# A module may require an older version of itself without error. This is +# inconsistent (the required version is never selected), but we still get +# a reproducible build list. +go list -m all +stdout '^golang.org/issue/46078$' -# A module that explicitly requires an older version of itself should be -# rejected as inconsistent: we enforce that every explicit requirement is the -# selected version of its module path, but the selected version of the main -# module is always itself — not some explicit version. - -! go list -m all -stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$' - - -# The suggested 'go mod tidy' command should succeed (not crash). - +# 'go mod tidy' should fix this (and not crash). go mod tidy diff --git a/libgo/go/io/fs/fs.go b/libgo/go/io/fs/fs.go index e1be32478e0..e603afadb0b 100644 --- a/libgo/go/io/fs/fs.go +++ b/libgo/go/io/fs/fs.go @@ -86,7 +86,7 @@ type File interface { type DirEntry interface { // Name returns the name of the file (or subdirectory) described by the entry. // This name is only the final element of the path (the base name), not the entire path. - // For example, Name would return "hello.go" not "/home/gopher/hello.go". + // For example, Name would return "hello.go" not "home/gopher/hello.go". Name() string // IsDir reports whether the entry describes a directory. diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index cae54643ddd..7e14749f838 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -6445,10 +6445,11 @@ func TestErrorWriteLoopRace(t *testing.T) { // Test that a new request which uses the connection of an active request // cannot cause it to be canceled as well. func TestCancelRequestWhenSharingConnection(t *testing.T) { - if testing.Short() { - t.Skip("skipping in short mode") - } + reqc := make(chan chan struct{}, 2) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) { + ch := make(chan struct{}, 1) + reqc <- ch + <-ch w.Header().Add("Content-Length", "0") })) defer ts.Close() @@ -6460,34 +6461,58 @@ func TestCancelRequestWhenSharingConnection(t *testing.T) { var wg sync.WaitGroup - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for ctx.Err() == nil { - reqctx, reqcancel := context.WithCancel(ctx) - go reqcancel() - req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil) - res, err := client.Do(req) - if err == nil { - res.Body.Close() - } - } - }() - } - - for ctx.Err() == nil { - req, _ := NewRequest("GET", ts.URL, nil) - if res, err := client.Do(req); err != nil { - t.Errorf("unexpected: %p %v", req, err) - break - } else { + wg.Add(1) + putidlec := make(chan chan struct{}) + go func() { + defer wg.Done() + ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ + PutIdleConn: func(error) { + // Signal that the idle conn has been returned to the pool, + // and wait for the order to proceed. + ch := make(chan struct{}) + putidlec <- ch + <-ch + }, + }) + req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil) + res, err := client.Do(req) + if err == nil { res.Body.Close() } - } + if err != nil { + t.Errorf("request 1: got err %v, want nil", err) + } + }() + // Wait for the first request to receive a response and return the + // connection to the idle pool. + r1c := <-reqc + close(r1c) + idlec := <-putidlec + + wg.Add(1) + cancelctx, cancel := context.WithCancel(context.Background()) + go func() { + defer wg.Done() + req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil) + res, err := client.Do(req) + if err == nil { + res.Body.Close() + } + if !errors.Is(err, context.Canceled) { + t.Errorf("request 2: got err %v, want Canceled", err) + } + }() + + // Wait for the second request to arrive at the server, and then cancel + // the request context. + r2c := <-reqc cancel() + + // Give the cancelation a moment to take effect, and then unblock the first request. + time.Sleep(1 * time.Millisecond) + close(idlec) + + close(r2c) wg.Wait() } diff --git a/libgo/go/runtime/mfinal.go b/libgo/go/runtime/mfinal.go index 90598890fcb..b4afaee0613 100644 --- a/libgo/go/runtime/mfinal.go +++ b/libgo/go/runtime/mfinal.go @@ -402,6 +402,10 @@ okarg: // Without the KeepAlive call, the finalizer could run at the start of // syscall.Read, closing the file descriptor before syscall.Read makes // the actual system call. +// +// Note: KeepAlive should only be used to prevent finalizers from +// running prematurely. In particular, when used with unsafe.Pointer, +// the rules for valid uses of unsafe.Pointer still apply. func KeepAlive(x interface{}) { // Introduce a use of x that the compiler can't eliminate. // This makes sure x is alive on entry. We need x to be alive diff --git a/libgo/go/sync/atomic/value.go b/libgo/go/sync/atomic/value.go index 61f81d8fd37..3500cd22f4e 100644 --- a/libgo/go/sync/atomic/value.go +++ b/libgo/go/sync/atomic/value.go @@ -126,7 +126,7 @@ func (v *Value) Swap(new interface{}) (old interface{}) { } } -// CompareAndSwapPointer executes the compare-and-swap operation for the Value. +// CompareAndSwap executes the compare-and-swap operation for the Value. // // All calls to CompareAndSwap for a given Value must use values of the same // concrete type. CompareAndSwap of an inconsistent type panics, as does diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index bb173a21c2d..f4b4f48142f 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -77,9 +77,9 @@ import "errors" // The formats and 002 are space-padded and zero-padded // three-character day of year; there is no unpadded day of year format. // -// A decimal point followed by one or more zeros represents a fractional -// second, printed to the given number of decimal places. -// Either a comma or decimal point followed by one or more nines represents +// A comma or decimal point followed by one or more zeros represents +// a fractional second, printed to the given number of decimal places. +// A comma or decimal point followed by one or more nines represents // a fractional second, printed to the given number of decimal places, with // trailing zeros removed. // For example "15:04:05,000" or "15:04:05.000" formats or parses with diff --git a/libgo/misc/cgo/testsanitizers/msan_test.go b/libgo/misc/cgo/testsanitizers/msan_test.go index 2a3494fbfc1..5ee9947a585 100644 --- a/libgo/misc/cgo/testsanitizers/msan_test.go +++ b/libgo/misc/cgo/testsanitizers/msan_test.go @@ -42,6 +42,7 @@ func TestMSAN(t *testing.T) { {src: "msan5.go"}, {src: "msan6.go"}, {src: "msan7.go"}, + {src: "msan8.go"}, {src: "msan_fail.go", wantErr: true}, } for _, tc := range cases { diff --git a/libgo/misc/cgo/testsanitizers/testdata/msan8.go b/libgo/misc/cgo/testsanitizers/testdata/msan8.go new file mode 100644 index 00000000000..1cb5c5677fa --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/testdata/msan8.go @@ -0,0 +1,109 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +#include +#include +#include + +#include + +// cgoTracebackArg is the type of the argument passed to msanGoTraceback. +struct cgoTracebackArg { + uintptr_t context; + uintptr_t sigContext; + uintptr_t* buf; + uintptr_t max; +}; + +// msanGoTraceback is registered as the cgo traceback function. +// This will be called when a signal occurs. +void msanGoTraceback(void* parg) { + struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg); + arg->buf[0] = 0; +} + +// msanGoWait will be called with all registers undefined as far as +// msan is concerned. It just waits for a signal. +// Because the registers are msan-undefined, the signal handler will +// be invoked with all registers msan-undefined. +__attribute__((noinline)) +void msanGoWait(unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) { + sigset_t mask; + + sigemptyset(&mask); + sigsuspend(&mask); +} + +// msanGoSignalThread is the thread ID of the msanGoLoop thread. +static pthread_t msanGoSignalThread; + +// msanGoSignalThreadSet is used to record that msanGoSignalThread +// has been initialized. This is accessed atomically. +static int32_t msanGoSignalThreadSet; + +// uninit is explicitly poisoned, so that we can make all registers +// undefined by calling msanGoWait. +static unsigned long uninit; + +// msanGoLoop loops calling msanGoWait, with the arguments passed +// such that msan thinks that they are undefined. msan permits +// undefined values to be used as long as they are not used to +// for conditionals or for memory access. +void msanGoLoop() { + int i; + + msanGoSignalThread = pthread_self(); + __atomic_store_n(&msanGoSignalThreadSet, 1, __ATOMIC_SEQ_CST); + + // Force uninit to be undefined for msan. + __msan_poison(&uninit, sizeof uninit); + for (i = 0; i < 100; i++) { + msanGoWait(uninit, uninit, uninit, uninit, uninit, uninit); + } +} + +// msanGoReady returns whether msanGoSignalThread is set. +int msanGoReady() { + return __atomic_load_n(&msanGoSignalThreadSet, __ATOMIC_SEQ_CST) != 0; +} + +// msanGoSendSignal sends a signal to the msanGoLoop thread. +void msanGoSendSignal() { + pthread_kill(msanGoSignalThread, SIGWINCH); +} +*/ +import "C" + +import ( + "runtime" + "time" +) + +func main() { + runtime.SetCgoTraceback(0, C.msanGoTraceback, nil, nil) + + c := make(chan bool) + go func() { + defer func() { c <- true }() + C.msanGoLoop() + }() + + for C.msanGoReady() == 0 { + time.Sleep(time.Microsecond) + } + +loop: + for { + select { + case <-c: + break loop + default: + C.msanGoSendSignal() + time.Sleep(time.Microsecond) + } + } +}