Skip to content

testing/synctest: runtime.SetBlockProfileRate breaks promise with synctest.Wait #76286

Description

@Darkclainer

Go version

go version go1.25.2 X:nodwarf5 linux/amd64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/username/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/username/.config/go/env'
GOEXE=''
GOEXPERIMENT='nodwarf5'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3427196454=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/username/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/username/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/username/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.25.2 X:nodwarf5'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Hello! Here is a minimal test:

package main

import (
	"runtime"
	"testing"
	"testing/synctest"
)

func Test(t *testing.T) {
	synctest.Test(t, func(t *testing.T) {
		done := false
		go func() {  // the line below causes problem. Works only with rate > 1
			runtime.SetBlockProfileRate(2)
			done = true
		}()
		synctest.Wait()
		if !done {
			t.Fatal("somehow not done")
		}
	})
}

What did you see happen?

Test is flaky, needs to be run many times.

go test -v -count 1000  -failfast ./
=== RUN   Test
    main_test.go:18: somehow not done
--- FAIL: Test (0.00s)
panic: deadlock: main bubble goroutine has exited but blocked goroutines remain [recovered, repanicked]

goroutine 21 [running]:
testing.tRunner.func1.2({0x566980, 0xc0000ca0f0})
	/usr/lib/go/src/testing/testing.go:1872 +0x237
testing.tRunner.func1()
	/usr/lib/go/src/testing/testing.go:1875 +0x35b
panic({0x566980?, 0xc0000ca0f0?})
	/usr/lib/go/src/runtime/panic.go:783 +0x132
internal/synctest.Run(0xc0000aa160)
	/usr/lib/go/src/runtime/synctest.go:251 +0x2de
testing/synctest.Test(0xc000092c40, 0x58d2b8)
	/usr/lib/go/src/testing/synctest/synctest.go:282 +0x90
blockratetest.Test(0xc000092c40?)
	/home/blockratetest/main_test.go:10 +0x1a
testing.tRunner(0xc000092c40, 0x58d1d8)
	/usr/lib/go/src/testing/testing.go:1934 +0xea
created by testing.(*T).Run in goroutine 1
	/usr/lib/go/src/testing/testing.go:1997 +0x465

goroutine 24 [sleep (durable), synctest bubble 1]:
time.Sleep(0xf4240)
	/usr/lib/go/src/runtime/time.go:361 +0x145
runtime.SetBlockProfileRate(0x2)
	/usr/lib/go/src/runtime/mprof.go:497 +0x2c
blockratetest.Test.func1.1()
	/home/blockratetest/main_test.go:13 +0x25
created by blockratetest.Test.func1 in goroutine 23
	/home/blockratetest/main_test.go:12 +0x66
FAIL	blockratetest	0.005s
FAIL

What did you expect to see?

Test is almost copy of the example from https://pkg.go.dev/testing/synctest#hdr-Blocking .

It is not clear why calling runtime.SetBlockProfileRate causes test to fail - documentation of runtime/synctest package doesn't mention this behavior or it is not clear.

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    Status
    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions