]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: set raceignore to zero when starting a new goroutine
authorJelle van den Hooff <jelle@vandenhooff.name>
Thu, 22 Jun 2023 01:28:05 +0000 (18:28 -0700)
committerMichael Knyszek <mknyszek@google.com>
Fri, 23 Jun 2023 16:46:25 +0000 (16:46 +0000)
When reusing a g struct the runtime did not reset
g.raceignore. Initialize raceignore to zero when initially
setting racectx.

A goroutine can end with a non-zero raceignore if it exits
after calling runtime.RaceDisable without a matching
runtime.RaceEnable. If that goroutine's g is later reused
the race detector is in a weird state: the underlying
g.racectx is active, yet g.raceignore is non-zero, and
raceacquire/racerelease which check g.raceignore become
no-ops. This causes the race detector to report races when
there are none.

Fixes #60934

Change-Id: Ib8e412f11badbaf69a480f03740da70891f4093f
Reviewed-on: https://go-review.googlesource.com/c/go/+/505055
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Knyszek <mknyszek@google.com>

src/runtime/proc.go
src/runtime/race/testdata/mop_test.go

index 3cecd1a057de6264082a4954db4d7b349dbd94ad..9fd200ea329021ddd131e03afaae5855dcfc9edd 100644 (file)
@@ -4570,6 +4570,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g {
        pp.goidcache++
        if raceenabled {
                newg.racectx = racegostart(callerpc)
+               newg.raceignore = 0
                if newg.labels != nil {
                        // See note in proflabel.go on labelSync's role in synchronizing
                        // with the reads in the signal handler.
index 0da539fc01494d535b3f1af42df410c6428f1e1f..6b1069fcca2a81bae7e3558ff176d0f241c16e48 100644 (file)
@@ -2093,3 +2093,40 @@ func TestNoRaceTinyAlloc(t *testing.T) {
                <-done
        }
 }
+
+func TestNoRaceIssue60934(t *testing.T) {
+       // Test that runtime.RaceDisable state doesn't accidentally get applied to
+       // new goroutines.
+
+       // Create several goroutines that end after calling runtime.RaceDisable.
+       var wg sync.WaitGroup
+       ready := make(chan struct{})
+       wg.Add(32)
+       for i := 0; i < 32; i++ {
+               go func() {
+                       <-ready // ensure we have multiple goroutines running at the same time
+                       runtime.RaceDisable()
+                       wg.Done()
+               }()
+       }
+       close(ready)
+       wg.Wait()
+
+       // Make sure race detector still works. If the runtime.RaceDisable state
+       // leaks, the happens-before edges here will be ignored and a race on x will
+       // be reported.
+       var x int
+       ch := make(chan struct{}, 0)
+       wg.Add(2)
+       go func() {
+               x = 1
+               ch <- struct{}{}
+               wg.Done()
+       }()
+       go func() {
+               <-ch
+               _ = x
+               wg.Done()
+       }()
+       wg.Wait()
+}