libgo: update to Go 1.15.3 release
authorIan Lance Taylor <iant@golang.org>
Sat, 24 Oct 2020 21:47:44 +0000 (14:47 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 27 Oct 2020 20:58:02 +0000 (13:58 -0700)
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265717

27 files changed:
gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/VERSION
libgo/go/bytes/bytes.go
libgo/go/cmd/cgo/gcc.go
libgo/go/cmd/cgo/main.go
libgo/go/cmd/cgo/out.go
libgo/go/cmd/go/internal/base/goflags.go
libgo/go/cmd/go/internal/version/version.go
libgo/go/cmd/go/internal/work/init.go
libgo/go/cmd/go/testdata/script/version.txt
libgo/go/internal/bytealg/index_generic.go
libgo/go/internal/poll/fd_unix.go
libgo/go/runtime/chan.go
libgo/go/runtime/chan_test.go
libgo/go/runtime/export_test.go
libgo/go/runtime/internal/atomic/atomic_test.go
libgo/go/runtime/mpagealloc.go
libgo/go/runtime/proc_test.go
libgo/go/runtime/runtime2.go
libgo/go/runtime/select.go
libgo/go/runtime/trace/trace_stack_test.go
libgo/go/testing/benchmark.go
libgo/go/testing/sub_test.go
libgo/go/testing/testing.go
libgo/misc/cgo/test/testdata/issue41761.go [new file with mode: 0644]
libgo/misc/cgo/test/testdata/issue41761a/a.go [new file with mode: 0644]

index 7d06595450274e41d91e87b2878b33cada7c2314..1f65809fc81f010934229a167c3ade92ac2ca92d 100644 (file)
@@ -1,4 +1,4 @@
-957591b8a054b692d92203a2420851689875f9c5
+be0d2cc2df9f98d967c242594838f86362dae2e7
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index cfbf488398e145fd3e627d9852126e09815a93d9..4b158c05c6e12188ab748b7bf1f31352027746cc 100644 (file)
@@ -1,4 +1,4 @@
-9706f510a5e2754595d716bd64be8375997311fb
+1984ee00048b63eacd2155cd6d74a2d13e998272
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index c19def3de444fa5012ca599d7e8d16a14743ca8f..93c7b2d3d7865886f0961fe6d2bf582985e48b9e 100644 (file)
@@ -1 +1 @@
-go1.15.2
+go1.15.3
index aa07b9fbc1604804957d779e4f50b8e35293bfb4..ce52649f132bb9575beacdca5af912f97478bb32 100644 (file)
@@ -227,19 +227,26 @@ func IndexAny(s []byte, chars string) int {
                        continue
                }
                r, width = utf8.DecodeRune(s[i:])
-               if r == utf8.RuneError {
-                       for _, r = range chars {
-                               if r == utf8.RuneError {
+               if r != utf8.RuneError {
+                       // r is 2 to 4 bytes
+                       if len(chars) == width {
+                               if chars == string(r) {
                                        return i
                                }
+                               continue
+                       }
+                       // Use bytealg.IndexString for performance if available.
+                       if bytealg.MaxLen >= width {
+                               if bytealg.IndexString(chars, string(r)) >= 0 {
+                                       return i
+                               }
+                               continue
                        }
-                       continue
                }
-               // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
-               // package should not import the strings package, use bytealg.IndexString
-               // instead. And this does not seem to lose much performance.
-               if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
-                       return i
+               for _, ch := range chars {
+                       if r == ch {
+                               return i
+                       }
                }
        }
        return -1
@@ -304,19 +311,26 @@ func LastIndexAny(s []byte, chars string) int {
                }
                r, size := utf8.DecodeLastRune(s[:i])
                i -= size
-               if r == utf8.RuneError {
-                       for _, r = range chars {
-                               if r == utf8.RuneError {
+               if r != utf8.RuneError {
+                       // r is 2 to 4 bytes
+                       if len(chars) == size {
+                               if chars == string(r) {
                                        return i
                                }
+                               continue
+                       }
+                       // Use bytealg.IndexString for performance if available.
+                       if bytealg.MaxLen >= size {
+                               if bytealg.IndexString(chars, string(r)) >= 0 {
+                                       return i
+                               }
+                               continue
                        }
-                       continue
                }
-               // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
-               // package should not import the strings package, use bytealg.IndexString
-               // instead. And this does not seem to lose much performance.
-               if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
-                       return i
+               for _, ch := range chars {
+                       if r == ch {
+                               return i
+                       }
                }
        }
        return -1
index f774cbb9353d9ae0689b0de23d29a55ca0fa0d16..37bafcf189e55ea33e18805bc885eceb1a501e75 100644 (file)
@@ -2459,6 +2459,18 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
                        tt := *t
                        tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
                        tt.Go = c.Ident("struct{}")
+                       if dt.Kind == "struct" {
+                               // We don't know what the representation of this struct is, so don't let
+                               // anyone allocate one on the Go side. As a side effect of this annotation,
+                               // pointers to this type will not be considered pointers in Go. They won't
+                               // get writebarrier-ed or adjusted during a stack copy. This should handle
+                               // all the cases badPointerTypedef used to handle, but hopefully will
+                               // continue to work going forward without any more need for cgo changes.
+                               tt.NotInHeap = true
+                               // TODO: we should probably do the same for unions. Unions can't live
+                               // on the Go heap, right? It currently doesn't work for unions because
+                               // they are defined as a type alias for struct{}, not a defined type.
+                       }
                        typedef[name.Name] = &tt
                        break
                }
@@ -2529,6 +2541,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
                }
                t.Go = name
                t.BadPointer = sub.BadPointer
+               t.NotInHeap = sub.NotInHeap
                if unionWithPointer[sub.Go] {
                        unionWithPointer[t.Go] = true
                }
@@ -2539,6 +2552,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
                        tt := *t
                        tt.Go = sub.Go
                        tt.BadPointer = sub.BadPointer
+                       tt.NotInHeap = sub.NotInHeap
                        typedef[name.Name] = &tt
                }
 
@@ -3047,6 +3061,7 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
 // non-pointers in this type.
 // TODO: Currently our best solution is to find these manually and list them as
 // they come up. A better solution is desired.
+// Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file.
 func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
        if c.badCFType(dt) {
                return true
index 6de6d69ce6c832d39502bd40400b41946adb4bcc..7fc2508021be0598c4321682defddf341fb96f30 100644 (file)
@@ -151,7 +151,8 @@ type Type struct {
        Go         ast.Expr
        EnumValues map[string]int64
        Typedef    string
-       BadPointer bool
+       BadPointer bool // this pointer type should be represented as a uintptr (deprecated)
+       NotInHeap  bool // this type should have a go:notinheap annotation
 }
 
 // A FuncType collects information about a function type in both the C and Go worlds.
index 1d23fc1d255a2222473701482f97539953ffd091..dd03f7d67a5f093b1fede677baf68f4a693d3cbb 100644 (file)
@@ -113,6 +113,9 @@ func (p *Package) writeDefs() {
        sort.Strings(typedefNames)
        for _, name := range typedefNames {
                def := typedef[name]
+               if def.NotInHeap {
+                       fmt.Fprintf(fgo2, "//go:notinheap\n")
+               }
                fmt.Fprintf(fgo2, "type %s ", name)
                // We don't have source info for these types, so write them out without source info.
                // Otherwise types would look like:
index 34766134b090ff6e378d965a8232bac72f849224..f29cc3cf9a5d0d7be56a42cd50cc8e2108ccf00a 100644 (file)
@@ -153,3 +153,20 @@ func SetFromGOFLAGS(flags *flag.FlagSet) {
                }
        }
 }
+
+// InGOFLAGS returns whether GOFLAGS contains the given flag, such as "-mod".
+func InGOFLAGS(flag string) bool {
+       for _, goflag := range GOFLAGS() {
+               name := goflag
+               if strings.HasPrefix(name, "--") {
+                       name = name[1:]
+               }
+               if i := strings.Index(name, "="); i >= 0 {
+                       name = name[:i]
+               }
+               if name == flag {
+                       return true
+               }
+       }
+       return false
+}
index ac2ae501552926258ef63261be6fc0d92f8f170d..a5b13653cd6d39ce929f7ea96fc3aa55b2677411 100644 (file)
@@ -53,7 +53,14 @@ var (
 
 func runVersion(cmd *base.Command, args []string) {
        if len(args) == 0 {
-               if *versionM || *versionV {
+               // If any of this command's flags were passed explicitly, error
+               // out, because they only make sense with arguments.
+               //
+               // Don't error if the flags came from GOFLAGS, since that can be
+               // a reasonable use case. For example, imagine GOFLAGS=-v to
+               // turn "verbose mode" on for all Go commands, which should not
+               // break "go version".
+               if (!base.InGOFLAGS("-m") && *versionM) || (!base.InGOFLAGS("-v") && *versionV) {
                        fmt.Fprintf(os.Stderr, "go version: flags can only be used with arguments\n")
                        base.SetExitStatus(2)
                        return
index dad3b10111d0d1d177799849561a0bfd68e94990..c168364cd173a52ba19dee73ebb94383affd31ad 100644 (file)
@@ -254,34 +254,18 @@ func buildModeInit() {
        case "":
                // ok
        case "readonly", "vendor", "mod":
-               if !cfg.ModulesEnabled && !inGOFLAGS("-mod") {
+               if !cfg.ModulesEnabled && !base.InGOFLAGS("-mod") {
                        base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod)
                }
        default:
                base.Fatalf("-mod=%s not supported (can be '', 'mod', 'readonly', or 'vendor')", cfg.BuildMod)
        }
        if !cfg.ModulesEnabled {
-               if cfg.ModCacheRW && !inGOFLAGS("-modcacherw") {
+               if cfg.ModCacheRW && !base.InGOFLAGS("-modcacherw") {
                        base.Fatalf("build flag -modcacherw only valid when using modules")
                }
-               if cfg.ModFile != "" && !inGOFLAGS("-mod") {
+               if cfg.ModFile != "" && !base.InGOFLAGS("-mod") {
                        base.Fatalf("build flag -modfile only valid when using modules")
                }
        }
 }
-
-func inGOFLAGS(flag string) bool {
-       for _, goflag := range base.GOFLAGS() {
-               name := goflag
-               if strings.HasPrefix(name, "--") {
-                       name = name[1:]
-               }
-               if i := strings.Index(name, "="); i >= 0 {
-                       name = name[:i]
-               }
-               if name == flag {
-                       return true
-               }
-       }
-       return false
-}
index 0123ac6d53f3934fb4ca088e906436317b736ba5..87cb6befe932683733df2faac2270cc8bd3c8950 100644 (file)
@@ -9,6 +9,12 @@ stderr 'with arguments'
 ! go version -v
 stderr 'with arguments'
 
+# Neither of the two flags above should be an issue via GOFLAGS.
+env GOFLAGS='-m -v'
+go version
+stdout '^go version'
+env GOFLAGS=
+
 env GO111MODULE=on
 # Skip the builds below if we are running in short mode.
 [short] skip
index 3dc1c6b2232bb0b8efe730ca62bba8fb2c430bfc..c595c231cf019c4c88446c2f0fa311648f5f19f5 100644 (file)
@@ -17,42 +17,8 @@ func Index(a, b []byte) int {
 
 // IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
 // Requires 2 <= len(b) <= MaxLen.
-func IndexString(s, substr string) int {
-       // This is a partial copy of strings.Index, here because bytes.IndexAny and bytes.LastIndexAny
-       // call bytealg.IndexString. Some platforms have an optimized assembly version of this function.
-       // This implementation is used for those that do not. Although the pure Go implementation here
-       // works for the case of len(b) > MaxLen, we do not require that its assembly implementation also
-       // supports the case of len(b) > MaxLen. And we do not guarantee that this function supports the
-       // case of len(b) > MaxLen.
-       n := len(substr)
-       c0 := substr[0]
-       c1 := substr[1]
-       i := 0
-       t := len(s) - n + 1
-       fails := 0
-       for i < t {
-               if s[i] != c0 {
-                       o := IndexByteString(s[i:t], c0)
-                       if o < 0 {
-                               return -1
-                       }
-                       i += o
-               }
-               if s[i+1] == c1 && s[i:i+n] == substr {
-                       return i
-               }
-               i++
-               fails++
-               if fails >= 4+i>>4 && i < t {
-                       // See comment in src/bytes/bytes.go.
-                       j := IndexRabinKarp(s[i:], substr)
-                       if j < 0 {
-                               return -1
-                       }
-                       return i + j
-               }
-       }
-       return -1
+func IndexString(a, b string) int {
+       panic("unimplemented")
 }
 
 // Cutover reports the number of failures of IndexByte we should tolerate
index f177ccf3f6e8be0d451362fc10686e73d6dee25d..10cf1735d6acb043b53c9edf10ff6d3a3d962083 100644 (file)
@@ -152,7 +152,7 @@ func (fd *FD) Read(p []byte) (int, error) {
                p = p[:maxRW]
        }
        for {
-               n, err := ignoringEINTR(syscall.Read, fd.Sysfd, p)
+               n, err := ignoringEINTR(func() (int, error) { return syscall.Read(fd.Sysfd, p) })
                if err != nil {
                        n = 0
                        if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -264,7 +264,7 @@ func (fd *FD) Write(p []byte) (int, error) {
                if fd.IsStream && max-nn > maxRW {
                        max = nn + maxRW
                }
-               n, err := ignoringEINTR(syscall.Write, fd.Sysfd, p[nn:max])
+               n, err := ignoringEINTR(func() (int, error) { return syscall.Write(fd.Sysfd, p[nn:max]) })
                if n > 0 {
                        nn += n
                }
@@ -423,7 +423,7 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) {
        }
        defer fd.decref()
        for {
-               n, err := ignoringEINTR(syscall.ReadDirent, fd.Sysfd, buf)
+               n, err := ignoringEINTR(func() (int, error) { return syscall.ReadDirent(fd.Sysfd, buf) })
                if err != nil {
                        n = 0
                        if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -514,7 +514,7 @@ func (fd *FD) WriteOnce(p []byte) (int, error) {
                return 0, err
        }
        defer fd.writeUnlock()
-       return ignoringEINTR(syscall.Write, fd.Sysfd, p)
+       return ignoringEINTR(func() (int, error) { return syscall.Write(fd.Sysfd, p) })
 }
 
 // RawRead invokes the user-defined function f for a read operation.
@@ -562,9 +562,9 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error {
 // installed without setting SA_RESTART. None of these are the common case,
 // but there are enough of them that it seems that we can't avoid
 // an EINTR loop.
-func ignoringEINTR(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
+func ignoringEINTR(fn func() (int, error)) (int, error) {
        for {
-               n, err := fn(fd, p)
+               n, err := fn()
                if err != syscall.EINTR {
                        return n, err
                }
index de1d80acd306579eb03c294084dc3c11c1c85eb1..b909d478d266153ff70ce5bf4cca6db579da04b8 100644 (file)
@@ -267,6 +267,11 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
        gp.waiting = mysg
        gp.param = nil
        c.sendq.enqueue(mysg)
+       // Signal to anyone trying to shrink our stack that we're about
+       // to park on a channel. The window between when this G's status
+       // changes and when we set gp.activeStackChans is not safe for
+       // stack shrinking.
+       atomic.Store8(&gp.parkingOnChan, 1)
        gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2)
        // Ensure the value being sent is kept alive until the
        // receiver copies it out. The sudog has a pointer to the
@@ -586,6 +591,11 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
        mysg.c = c
        gp.param = nil
        c.recvq.enqueue(mysg)
+       // Signal to anyone trying to shrink our stack that we're about
+       // to park on a channel. The window between when this G's status
+       // changes and when we set gp.activeStackChans is not safe for
+       // stack shrinking.
+       atomic.Store8(&gp.parkingOnChan, 1)
        gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceEvGoBlockRecv, 2)
 
        // someone woke us up
@@ -663,7 +673,19 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
 func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool {
        // There are unlocked sudogs that point into gp's stack. Stack
        // copying must lock the channels of those sudogs.
+       // Set activeStackChans here instead of before we try parking
+       // because we could self-deadlock in stack growth on the
+       // channel lock.
        gp.activeStackChans = true
+       // Mark that it's safe for stack shrinking to occur now,
+       // because any thread acquiring this G's stack for shrinking
+       // is guaranteed to observe activeStackChans after this store.
+       atomic.Store8(&gp.parkingOnChan, 0)
+       // Make sure we unlock after setting activeStackChans and
+       // unsetting parkingOnChan. The moment we unlock chanLock
+       // we risk gp getting readied by a channel operation and
+       // so gp could continue running before everything before
+       // the unlock is visible (even to gp itself).
        unlock((*mutex)(chanLock))
        return true
 }
index ac81d409bda91f489879d620329874a90722cacf..85d3e04ffff4a26d54db4692c340544346787873 100644 (file)
@@ -628,6 +628,62 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) {
        <-done
 }
 
+func TestNoShrinkStackWhileParking(t *testing.T) {
+       // The goal of this test is to trigger a "racy sudog adjustment"
+       // throw. Basically, there's a window between when a goroutine
+       // becomes available for preemption for stack scanning (and thus,
+       // stack shrinking) but before the goroutine has fully parked on a
+       // channel. See issue 40641 for more details on the problem.
+       //
+       // The way we try to induce this failure is to set up two
+       // goroutines: a sender and a reciever that communicate across
+       // a channel. We try to set up a situation where the sender
+       // grows its stack temporarily then *fully* blocks on a channel
+       // often. Meanwhile a GC is triggered so that we try to get a
+       // mark worker to shrink the sender's stack and race with the
+       // sender parking.
+       //
+       // Unfortunately the race window here is so small that we
+       // either need a ridiculous number of iterations, or we add
+       // "usleep(1000)" to park_m, just before the unlockf call.
+       const n = 10
+       send := func(c chan<- int, done chan struct{}) {
+               for i := 0; i < n; i++ {
+                       c <- i
+                       // Use lots of stack briefly so that
+                       // the GC is going to want to shrink us
+                       // when it scans us. Make sure not to
+                       // do any function calls otherwise
+                       // in order to avoid us shrinking ourselves
+                       // when we're preempted.
+                       stackGrowthRecursive(20)
+               }
+               done <- struct{}{}
+       }
+       recv := func(c <-chan int, done chan struct{}) {
+               for i := 0; i < n; i++ {
+                       // Sleep here so that the sender always
+                       // fully blocks.
+                       time.Sleep(10 * time.Microsecond)
+                       <-c
+               }
+               done <- struct{}{}
+       }
+       for i := 0; i < n*20; i++ {
+               c := make(chan int)
+               done := make(chan struct{})
+               go recv(c, done)
+               go send(c, done)
+               // Wait a little bit before triggering
+               // the GC to make sure the sender and
+               // reciever have gotten into their groove.
+               time.Sleep(50 * time.Microsecond)
+               runtime.GC()
+               <-done
+               <-done
+       }
+}
+
 func TestSelectDuplicateChannel(t *testing.T) {
        // This test makes sure we can queue a G on
        // the same channel multiple times.
index 482d014ad58151c491d350f6c269fa5f5c9cd6c4..369230a8b7b023d2b050b3e504d3e6322485be27 100644 (file)
@@ -355,7 +355,11 @@ func ReadMemStatsSlow() (base, slow MemStats) {
                }
 
                for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
-                       pg := mheap_.pages.chunkOf(i).scavenged.popcntRange(0, pallocChunkPages)
+                       chunk := mheap_.pages.tryChunkOf(i)
+                       if chunk == nil {
+                               continue
+                       }
+                       pg := chunk.scavenged.popcntRange(0, pallocChunkPages)
                        slow.HeapReleased += uint64(pg) * pageSize
                }
                for _, p := range allp {
@@ -752,11 +756,7 @@ func (p *PageAlloc) InUse() []AddrRange {
 // Returns nil if the PallocData's L2 is missing.
 func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
        ci := chunkIdx(i)
-       l2 := (*pageAlloc)(p).chunks[ci.l1()]
-       if l2 == nil {
-               return nil
-       }
-       return (*PallocData)(&l2[ci.l2()])
+       return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
 }
 
 // AddrRange represents a range over addresses.
@@ -896,7 +896,10 @@ func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
                lock(&mheap_.lock)
        chunkLoop:
                for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
-                       chunk := mheap_.pages.chunkOf(i)
+                       chunk := mheap_.pages.tryChunkOf(i)
+                       if chunk == nil {
+                               continue
+                       }
                        for j := 0; j < pallocChunkPages/64; j++ {
                                // Run over each 64-bit bitmap section and ensure
                                // scavenged is being cleared properly on allocation.
@@ -977,10 +980,9 @@ func MapHashCheck(m interface{}, k interface{}) (uintptr, uintptr) {
 }
 
 func MSpanCountAlloc(bits []byte) int {
-       s := mspan{
-               nelems:     uintptr(len(bits) * 8),
-               gcmarkBits: (*gcBits)(unsafe.Pointer(&bits[0])),
-       }
+       s := (*mspan)(mheap_.spanalloc.alloc())
+       s.nelems = uintptr(len(bits) * 8)
+       s.gcmarkBits = (*gcBits)(unsafe.Pointer(&bits[0]))
        return s.countAlloc()
 }
 
index 0c1125c55831b663f29c278fbff532a22ce8c75d..b0a8fa06103ff2bf5e6c0c694e67d5e1190b08a9 100644 (file)
@@ -220,3 +220,13 @@ func TestBitwiseContended(t *testing.T) {
                }
        }
 }
+
+func TestStorepNoWB(t *testing.T) {
+       var p [2]*int
+       for i := range p {
+               atomic.StorepNoWB(unsafe.Pointer(&p[i]), unsafe.Pointer(new(int)))
+       }
+       if p[0] == p[1] {
+               t.Error("Bad escape analysis of StorepNoWB")
+       }
+}
index 8b3c62c375e76f2efbd1f08a566af86b86954eaf..c90a6378bdacecaaa65370e5cc6c0a91d3eb3622 100644 (file)
@@ -326,7 +326,20 @@ func (s *pageAlloc) init(mheapLock *mutex, sysStat *uint64) {
        s.scav.scavLWM = maxSearchAddr
 }
 
+// tryChunkOf returns the bitmap data for the given chunk.
+//
+// Returns nil if the chunk data has not been mapped.
+func (s *pageAlloc) tryChunkOf(ci chunkIdx) *pallocData {
+       l2 := s.chunks[ci.l1()]
+       if l2 == nil {
+               return nil
+       }
+       return &l2[ci.l2()]
+}
+
 // chunkOf returns the chunk at the given chunk index.
+//
+// The chunk index must be valid or this method may throw.
 func (s *pageAlloc) chunkOf(ci chunkIdx) *pallocData {
        return &s.chunks[ci.l1()][ci.l2()]
 }
index b9828d981834a5d57853bdaba36a6556998ef0b1..a8f0dc39c0c7da39c44dbd2a394cd46066c689e8 100644 (file)
@@ -529,9 +529,17 @@ func BenchmarkPingPongHog(b *testing.B) {
        <-done
 }
 
+var padData [128]uint64
+
 func stackGrowthRecursive(i int) {
        var pad [128]uint64
-       if i != 0 && pad[0] == 0 {
+       pad = padData
+       for j := range pad {
+               if pad[j] != 0 {
+                       return
+               }
+       }
+       if i != 0 {
                stackGrowthRecursive(i - 1)
        }
 }
index 5029dbad027562ba0eb0038cc8ae2c135d508c04..bf3fbac14c8fc5b6a675860735aad72f4aad53e2 100644 (file)
@@ -450,6 +450,10 @@ type g struct {
        // copying needs to acquire channel locks to protect these
        // areas of the stack.
        activeStackChans bool
+       // parkingOnChan indicates that the goroutine is about to
+       // park on a chansend or chanrecv. Used to signal an unsafe point
+       // for stack shrinking. It's a boolean value, but is updated atomically.
+       parkingOnChan uint8
 
        raceignore     int8     // ignore race detection events
        sysblocktraced bool     // StartTrace has emitted EvGoInSyscall about this goroutine
@@ -940,11 +944,6 @@ type _defer struct {
 
 // panics
 // This is the gccgo version.
-//
-// This is marked go:notinheap because _panic values must only ever
-// live on the stack.
-//
-//go:notinheap
 type _panic struct {
        // The next entry in the stack.
        link *_panic
index cf5d0c75a494bff007701a6571622ace705ab3d2..c8910b8dc237f7a5fc2cc375f3ced8fc08c0ba10 100644 (file)
@@ -7,6 +7,7 @@ package runtime
 // This file contains the implementation of Go select statements.
 
 import (
+       "runtime/internal/atomic"
        "unsafe"
 )
 
@@ -72,7 +73,20 @@ func selunlock(scases []scase, lockorder []uint16) {
 func selparkcommit(gp *g, _ unsafe.Pointer) bool {
        // There are unlocked sudogs that point into gp's stack. Stack
        // copying must lock the channels of those sudogs.
+       // Set activeStackChans here instead of before we try parking
+       // because we could self-deadlock in stack growth on a
+       // channel lock.
        gp.activeStackChans = true
+       // Mark that it's safe for stack shrinking to occur now,
+       // because any thread acquiring this G's stack for shrinking
+       // is guaranteed to observe activeStackChans after this store.
+       atomic.Store8(&gp.parkingOnChan, 0)
+       // Make sure we unlock after setting activeStackChans and
+       // unsetting parkingOnChan. The moment we unlock any of the
+       // channel locks we risk gp getting readied by a channel operation
+       // and so gp could continue running before everything before the
+       // unlock is visible (even to gp itself).
+
        // This must not access gp's stack (see gopark). In
        // particular, it must not access the *hselect. That's okay,
        // because by the time this is called, gp.waiting has all
@@ -313,6 +327,11 @@ loop:
 
        // wait for someone to wake us up
        gp.param = nil
+       // Signal to anyone trying to shrink our stack that we're about
+       // to park on a channel. The window between when this G's status
+       // changes and when we set gp.activeStackChans is not safe for
+       // stack shrinking.
+       atomic.Store8(&gp.parkingOnChan, 1)
        gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1)
        gp.activeStackChans = false
 
index cfc0419b72c67cb26374551f58d440f6ce703e18..f856fdcd010f1e98cd692c36825f121df31b961e 100644 (file)
@@ -252,6 +252,7 @@ func TestTraceSymbolize(t *testing.T) {
                        {trace.EvGoSysCall, []frame{
                                {"syscall.read", 0},
                                {"syscall.Read", 0},
+                               {"internal/poll.(*FD).Read.func1", 0},
                                {"internal/poll.ignoringEINTR", 0},
                                {"internal/poll.(*FD).Read", 0},
                                {"os.(*File).read", 0},
index 52766005bf6595b99808b2633afe78f8aee14cdb..e9687bf26def25a3b91beebda27529a507cf3e22 100644 (file)
@@ -242,7 +242,7 @@ func (b *B) run1() bool {
                if b.skipped {
                        tag = "SKIP"
                }
-               if b.chatty && (len(b.output) > 0 || b.finished) {
+               if b.chatty != nil && (len(b.output) > 0 || b.finished) {
                        b.trimOutput()
                        fmt.Fprintf(b.w, "--- %s: %s\n%s", tag, b.name, b.output)
                }
@@ -523,10 +523,9 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
        }
        main := &B{
                common: common{
-                       name:   "Main",
-                       w:      os.Stdout,
-                       chatty: *chatty,
-                       bench:  true,
+                       name:  "Main",
+                       w:     os.Stdout,
+                       bench: true,
                },
                importPath: importPath,
                benchFunc: func(b *B) {
@@ -537,6 +536,9 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
                benchTime: benchTime,
                context:   ctx,
        }
+       if Verbose() {
+               main.chatty = newChattyPrinter(main.w)
+       }
        main.runN(1)
        return !main.failed
 }
@@ -549,7 +551,7 @@ func (ctx *benchContext) processBench(b *B) {
                        benchName := benchmarkName(b.name, procs)
 
                        // If it's chatty, we've already printed this information.
-                       if !b.chatty {
+                       if b.chatty == nil {
                                fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName)
                        }
                        // Recompute the running time for all but the first iteration.
@@ -576,7 +578,7 @@ func (ctx *benchContext) processBench(b *B) {
                                continue
                        }
                        results := r.String()
-                       if b.chatty {
+                       if b.chatty != nil {
                                fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName)
                        }
                        if *benchmarkMemory || b.showAllocResult {
@@ -639,7 +641,7 @@ func (b *B) Run(name string, f func(b *B)) bool {
                atomic.StoreInt32(&sub.hasSub, 1)
        }
 
-       if b.chatty {
+       if b.chatty != nil {
                labelsOnce.Do(func() {
                        fmt.Printf("goos: %s\n", runtime.GOOS)
                        fmt.Printf("goarch: %s\n", runtime.GOARCH)
index 8eb0084b1c84be712bf07f265f36dfc6a322b26b..5ed3fc4afec78856254c9e4bf3f5369a77716ed4 100644 (file)
@@ -483,10 +483,12 @@ func TestTRun(t *T) {
                                        signal: make(chan bool),
                                        name:   "Test",
                                        w:      buf,
-                                       chatty: tc.chatty,
                                },
                                context: ctx,
                        }
+                       if tc.chatty {
+                               root.chatty = newChattyPrinter(root.w)
+                       }
                        ok := root.Run(tc.desc, tc.f)
                        ctx.release()
 
@@ -665,11 +667,13 @@ func TestBRun(t *T) {
                                        signal: make(chan bool),
                                        name:   "root",
                                        w:      buf,
-                                       chatty: tc.chatty,
                                },
                                benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
                                benchTime: benchTimeFlag{d: 1 * time.Microsecond},
                        }
+                       if tc.chatty {
+                               root.chatty = newChattyPrinter(root.w)
+                       }
                        root.runN(1)
                        if ok != !tc.failed {
                                t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
@@ -741,9 +745,13 @@ func TestParallelSub(t *T) {
        }
 }
 
-type funcWriter func([]byte) (int, error)
+type funcWriter struct {
+       write func([]byte) (int, error)
+}
 
-func (fw funcWriter) Write(b []byte) (int, error) { return fw(b) }
+func (fw *funcWriter) Write(b []byte) (int, error) {
+       return fw.write(b)
+}
 
 func TestRacyOutput(t *T) {
        var runs int32  // The number of running Writes
@@ -761,9 +769,10 @@ func TestRacyOutput(t *T) {
 
        var wg sync.WaitGroup
        root := &T{
-               common:  common{w: funcWriter(raceDetector), chatty: true},
+               common:  common{w: &funcWriter{raceDetector}},
                context: newTestContext(1, newMatcher(regexp.MatchString, "", "")),
        }
+       root.chatty = newChattyPrinter(root.w)
        root.Run("", func(t *T) {
                for i := 0; i < 100; i++ {
                        wg.Add(1)
index fe6929d1ba0449b200479eb3a29bc6a957605139..80282fca60f39ab71ce1902f54fa3fe17a4bb247 100644 (file)
@@ -325,7 +325,6 @@ var (
        cpuListStr           *string
        parallel             *int
        testlog              *string
-       printer              *testPrinter
 
        haveExamples bool // are there examples?
 
@@ -335,55 +334,45 @@ var (
        numFailed uint32 // number of test failures
 )
 
-type testPrinter struct {
-       chatty bool
-
+type chattyPrinter struct {
+       w          io.Writer
        lastNameMu sync.Mutex // guards lastName
        lastName   string     // last printed test name in chatty mode
 }
 
-func newTestPrinter(chatty bool) *testPrinter {
-       return &testPrinter{
-               chatty: chatty,
-       }
+func newChattyPrinter(w io.Writer) *chattyPrinter {
+       return &chattyPrinter{w: w}
 }
 
-func (p *testPrinter) Print(testName, out string) {
-       p.Fprint(os.Stdout, testName, out)
+// Updatef prints a message about the status of the named test to w.
+//
+// The formatted message must include the test name itself.
+func (p *chattyPrinter) Updatef(testName, format string, args ...interface{}) {
+       p.lastNameMu.Lock()
+       defer p.lastNameMu.Unlock()
+
+       // Since the message already implies an association with a specific new test,
+       // we don't need to check what the old test name was or log an extra CONT line
+       // for it. (We're updating it anyway, and the current message already includes
+       // the test name.)
+       p.lastName = testName
+       fmt.Fprintf(p.w, format, args...)
 }
 
-func (p *testPrinter) Fprint(w io.Writer, testName, out string) {
+// Printf prints a message, generated by the named test, that does not
+// necessarily mention that tests's name itself.
+func (p *chattyPrinter) Printf(testName, format string, args ...interface{}) {
        p.lastNameMu.Lock()
        defer p.lastNameMu.Unlock()
 
-       if !p.chatty ||
-               strings.HasPrefix(out, "--- PASS: ") ||
-               strings.HasPrefix(out, "--- FAIL: ") ||
-               strings.HasPrefix(out, "--- SKIP: ") ||
-               strings.HasPrefix(out, "=== RUN   ") ||
-               strings.HasPrefix(out, "=== CONT  ") ||
-               strings.HasPrefix(out, "=== PAUSE ") {
-               // If we're buffering test output (!p.chatty), we don't really care which
-               // test is emitting which line so long as they are serialized.
-               //
-               // If the message already implies an association with a specific new test,
-               // we don't need to check what the old test name was or log an extra CONT
-               // line for it. (We're updating it anyway, and the current message already
-               // includes the test name.)
-               p.lastName = testName
-               fmt.Fprint(w, out)
-               return
-       }
-
        if p.lastName == "" {
                p.lastName = testName
        } else if p.lastName != testName {
-               // Always printed as-is, with 0 decoration or indentation. So, we skip
-               // printing to w.
-               fmt.Printf("=== CONT  %s\n", testName)
+               fmt.Fprintf(p.w, "=== CONT  %s\n", testName)
                p.lastName = testName
        }
-       fmt.Fprint(w, out)
+
+       fmt.Fprintf(p.w, format, args...)
 }
 
 // The maximum number of stack frames to go through when skipping helper functions for
@@ -405,12 +394,12 @@ type common struct {
        cleanupName string              // Name of the cleanup function.
        cleanupPc   []uintptr           // The stack trace at the point where Cleanup was called.
 
-       chatty     bool   // A copy of the chatty flag.
-       bench      bool   // Whether the current test is a benchmark.
-       finished   bool   // Test function has completed.
-       hasSub     int32  // Written atomically.
-       raceErrors int    // Number of races detected during test.
-       runner     string // Function name of tRunner running the test.
+       chatty     *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
+       bench      bool           // Whether the current test is a benchmark.
+       finished   bool           // Test function has completed.
+       hasSub     int32          // Written atomically.
+       raceErrors int            // Number of races detected during test.
+       runner     string         // Function name of tRunner running the test.
 
        parent   *common
        level    int       // Nesting depth of test or benchmark.
@@ -572,12 +561,31 @@ func (c *common) flushToParent(testName, format string, args ...interface{}) {
        p.mu.Lock()
        defer p.mu.Unlock()
 
-       printer.Fprint(p.w, testName, fmt.Sprintf(format, args...))
-
        c.mu.Lock()
        defer c.mu.Unlock()
-       io.Copy(p.w, bytes.NewReader(c.output))
-       c.output = c.output[:0]
+
+       if len(c.output) > 0 {
+               format += "%s"
+               args = append(args[:len(args):len(args)], c.output)
+               c.output = c.output[:0] // but why?
+       }
+
+       if c.chatty != nil && p.w == c.chatty.w {
+               // We're flushing to the actual output, so track that this output is
+               // associated with a specific test (and, specifically, that the next output
+               // is *not* associated with that test).
+               //
+               // Moreover, if c.output is non-empty it is important that this write be
+               // atomic with respect to the output of other tests, so that we don't end up
+               // with confusing '=== CONT' lines in the middle of our '--- PASS' block.
+               // Neither humans nor cmd/test2json can parse those easily.
+               // (See https://golang.org/issue/40771.)
+               c.chatty.Updatef(testName, format, args...)
+       } else {
+               // We're flushing to the output buffer of the parent test, which will
+               // itself follow a test-name header when it is finally flushed to stdout.
+               fmt.Fprintf(p.w, format, args...)
+       }
 }
 
 type indenter struct {
@@ -746,13 +754,13 @@ func (c *common) logDepth(s string, depth int) {
                }
                panic("Log in goroutine after " + c.name + " has completed")
        } else {
-               if c.chatty {
+               if c.chatty != nil {
                        if c.bench {
                                // Benchmarks don't print === CONT, so we should skip the test
                                // printer and just print straight to stdout.
                                fmt.Print(c.decorate(s, depth+1))
                        } else {
-                               printer.Print(c.name, c.decorate(s, depth+1))
+                               c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
                        }
 
                        return
@@ -1019,34 +1027,22 @@ func (t *T) Parallel() {
        t.parent.sub = append(t.parent.sub, t)
        t.raceErrors += race.Errors()
 
-       if t.chatty {
-               // Print directly to root's io.Writer so there is no delay.
-               root := t.parent
-               for ; root.parent != nil; root = root.parent {
-               }
-               root.mu.Lock()
+       if t.chatty != nil {
                // Unfortunately, even though PAUSE indicates that the named test is *no
                // longer* running, cmd/test2json interprets it as changing the active test
                // for the purpose of log parsing. We could fix cmd/test2json, but that
                // won't fix existing deployments of third-party tools that already shell
                // out to older builds of cmd/test2json — so merely fixing cmd/test2json
                // isn't enough for now.
-               printer.Fprint(root.w, t.name, fmt.Sprintf("=== PAUSE %s\n", t.name))
-               root.mu.Unlock()
+               t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
        }
 
        t.signal <- true   // Release calling test.
        <-t.parent.barrier // Wait for the parent test to complete.
        t.context.waitParallel()
 
-       if t.chatty {
-               // Print directly to root's io.Writer so there is no delay.
-               root := t.parent
-               for ; root.parent != nil; root = root.parent {
-               }
-               root.mu.Lock()
-               printer.Fprint(root.w, t.name, fmt.Sprintf("=== CONT  %s\n", t.name))
-               root.mu.Unlock()
+       if t.chatty != nil {
+               t.chatty.Updatef(t.name, "=== CONT  %s\n", t.name)
        }
 
        t.start = time.Now()
@@ -1197,14 +1193,8 @@ func (t *T) Run(name string, f func(t *T)) bool {
        }
        t.w = indenter{&t.common}
 
-       if t.chatty {
-               // Print directly to root's io.Writer so there is no delay.
-               root := t.parent
-               for ; root.parent != nil; root = root.parent {
-               }
-               root.mu.Lock()
-               printer.Fprint(root.w, t.name, fmt.Sprintf("=== RUN   %s\n", t.name))
-               root.mu.Unlock()
+       if t.chatty != nil {
+               t.chatty.Updatef(t.name, "=== RUN   %s\n", t.name)
        }
        // Instead of reducing the running count of this test before calling the
        // tRunner and increasing it afterwards, we rely on tRunner keeping the
@@ -1369,8 +1359,6 @@ func (m *M) Run() (code int) {
                flag.Parse()
        }
 
-       printer = newTestPrinter(Verbose())
-
        if *parallel < 1 {
                fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
                flag.Usage()
@@ -1415,7 +1403,7 @@ func (t *T) report() {
        format := "--- %s: %s (%s)\n"
        if t.Failed() {
                t.flushToParent(t.name, format, "FAIL", t.name, dstr)
-       } else if t.chatty {
+       } else if t.chatty != nil {
                if t.Skipped() {
                        t.flushToParent(t.name, format, "SKIP", t.name, dstr)
                } else {
@@ -1476,10 +1464,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
                                        signal:  make(chan bool),
                                        barrier: make(chan bool),
                                        w:       os.Stdout,
-                                       chatty:  *chatty,
                                },
                                context: ctx,
                        }
+                       if Verbose() {
+                               t.chatty = newChattyPrinter(t.w)
+                       }
                        tRunner(t, func(t *T) {
                                for _, test := range tests {
                                        t.Run(test.Name, test.F)
diff --git a/libgo/misc/cgo/test/testdata/issue41761.go b/libgo/misc/cgo/test/testdata/issue41761.go
new file mode 100644 (file)
index 0000000..919c749
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2020 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 cgotest
+
+/*
+   typedef struct S S;
+*/
+import "C"
+
+import (
+       "cgotest/issue41761a"
+       "testing"
+)
+
+func test41761(t *testing.T) {
+       var x issue41761a.T
+       _ = (*C.struct_S)(x.X)
+}
diff --git a/libgo/misc/cgo/test/testdata/issue41761a/a.go b/libgo/misc/cgo/test/testdata/issue41761a/a.go
new file mode 100644 (file)
index 0000000..ca5c181
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2020 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 issue41761a
+
+/*
+   typedef struct S S;
+*/
+import "C"
+
+type T struct {
+       X *C.S
+}