diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2025-02-25 22:50:10 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-05-14 19:12:19 -0700 |
| commit | 3ea94ae446727ab75f6baa38444cf49041cb3b16 (patch) | |
| tree | 78f4f5f812c01ddf21cc946b3f8a507369e28d1e /src/runtime/race/testdata | |
| parent | b30fa1bcc411f3a65a6e8f40ff3acdb1526ce0d0 (diff) | |
| download | go-3ea94ae446727ab75f6baa38444cf49041cb3b16.tar.xz | |
runtime: help the race detector detect possible concurrent cleanups
This change makes it so that cleanup goroutines, in race mode, create a
fake race context and switch to it, emulating cleanups running on new
goroutines. This helps in catching races between cleanups that might run
concurrently.
Change-Id: I4c4e33054313798d4ac4e5d91ff2487ea3eb4b16
Reviewed-on: https://go-review.googlesource.com/c/go/+/652635
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/race/testdata')
| -rw-r--r-- | src/runtime/race/testdata/finalizer_test.go | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/runtime/race/testdata/finalizer_test.go b/src/runtime/race/testdata/finalizer_test.go index 3ac33d2b59..ad6fe717c6 100644 --- a/src/runtime/race/testdata/finalizer_test.go +++ b/src/runtime/race/testdata/finalizer_test.go @@ -9,6 +9,7 @@ import ( "sync" "testing" "time" + "unsafe" ) func TestNoRaceFin(t *testing.T) { @@ -66,3 +67,43 @@ func TestRaceFin(t *testing.T) { time.Sleep(100 * time.Millisecond) y = 66 } + +func TestNoRaceCleanup(t *testing.T) { + c := make(chan bool) + go func() { + x := new(string) + y := new(string) + runtime.AddCleanup(x, func(y *string) { + *y = "foo" + }, y) + *y = "bar" + runtime.KeepAlive(x) + c <- true + }() + <-c + runtime.GC() + time.Sleep(100 * time.Millisecond) +} + +func TestRaceBetweenCleanups(t *testing.T) { + // Allocate struct with pointer to avoid hitting tinyalloc. + // Otherwise we can't be sure when the allocation will + // be freed. + type T struct { + v int + p unsafe.Pointer + } + sharedVar := new(int) + v0 := new(T) + v1 := new(T) + cleanup := func(x int) { + *sharedVar = x + } + runtime.AddCleanup(v0, cleanup, 0) + runtime.AddCleanup(v1, cleanup, 0) + v0 = nil + v1 = nil + + runtime.GC() + time.Sleep(100 * time.Millisecond) +} |
