Skip to content

runtime: goroutines that stop after calling runtime.RaceDisable break race detector  #60934

@jellevandenhooff

Description

@jellevandenhooff

What version of Go are you using (go version)?

$ go version
go version go1.20.5 darwin/arm64

Does this issue reproduce with the latest release?

Yes, reproduces on tip.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/jelle/Library/Caches/go-build"
GOENV="/Users/jelle/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/jelle/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/jelle/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.20.5/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.20.5/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.5"
GCCGO="gccgo"
AR="ar"
CC="cc"
CXX="c++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/rr/r3bbgb153sq467ngl1m0q3z00000gn/T/go-build2978985759=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I am using the race detector in a rather tricky setting: I call runtime.RaceDisable and runtime.RaceEnable to have the race detector ignore certain happens-before edges. If a goroutine stops after calling runtime.RaceDisable, but before calling runtime.RaceEnable because it panics, the race detector is broken afterwards.

Calling runtime.RaceDisable causes problems because it tracks state in a per-g field g.raceignore that does not get reset when the g is reused by a later new goroutine.

This program reproduces the issue:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	// create several gs that have mismatched RaceDisable/RaceEnable
	for i := 0; i < 100; i++ {
		go func() {
			// make sure gs run in parallel by sleeping
			time.Sleep(10 * time.Millisecond)

			runtime.RaceDisable()
		}()
	}

	// wait for all gs above to finish
	time.Sleep(20 * time.Millisecond)

	// shared variable protected by reading/writing ch
	var x int
	ch := make(chan struct{}, 0)

	go func() {
		x = 1
		ch <- struct{}{}
	}()
	go func() {
		<-ch
		_ = x
	}()

	time.Sleep(20 * time.Millisecond)
	fmt.Println("done")
}

What did you expect to see?

$ go run -race .
done

What did you see instead?

$ go run -race .
==================
WARNING: DATA RACE
Read at 0x00c0000ba008 by goroutine 110:
  main.main.func3()
      /Users/jelle/hack/go-bugs/raceenable/main.go:33 +0x40

Previous write at 0x00c0000ba008 by goroutine 109:
  main.main.func2()
      /Users/jelle/hack/go-bugs/raceenable/main.go:28 +0x34

Goroutine 110 (running) created at:
  main.main()
      /Users/jelle/hack/go-bugs/raceenable/main.go:31 +0x1c4

Goroutine 109 (finished) created at:
  main.main()
      /Users/jelle/hack/go-bugs/raceenable/main.go:27 +0x124
==================
done
Found 1 data race(s)
exit status 66

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.RaceDetectorcompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions