-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
testing: "panic: Log in goroutine after Test..." is unreliable due to lack of synchronization on t.done #67701
Comments
Added a proof-of-concept fix over in #67796 |
Change https://go.dev/cl/590055 mentions this issue: |
sort of related, I'm curious why this minor modification doesn't trigger the race detector: var done = make(chan struct{})
func TestMain(m *testing.M) {
m.Run()
fmt.Println(done)
}
func TestABefore(t *testing.T) {
go func() {
time.Sleep(10 * time.Millisecond)
done = nil
fmt.Println("goroutine done")
}()
time.Sleep(time.Millisecond)
}
func TestZLater(t *testing.T) {
time.Sleep(time.Second)
} but removing the It seems like this should be a fairly provable race, since nothing at all synchronizes between the assignment and the TestMain read. |
@Groxx That is most likely because running a test actually involves a couple of goroutines that synchronize with each other. Doing that synchronization around running |
Go version
go1.22.3 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
Despite clearly logging after the test has completed, this test does not reliably fail, depending on other code in the test and elsewhere. And when it does not fail,
t.Logf("too late")
is silently not logged anywhere.This is hard to reliably reproduce, but the cause is fairly straightforward: whether it logs or panics is determined by checking
t.done
inside the test's mutex, butt.done
is changed outside the mutex, so that value change may not propagate to the goroutine that produces the faulty log.Forcing a happens-after relationship reliably causes failure:
As much as I am fond of this race-detecting trick, and appreciate the issues it catches:
https://github.com/golang/go/blob/master/src/testing/testing.go#L1675-L1677
I feel like this log-failure-flakiness is an unintended consequence. Maybe the race-detecting access could be moved to a different field, rather than one that has a rather significant impact on behavior?
It's also strange to me that this doesn't seem to be (reliably) catching this race - is that happening inside
t.checkRaces()
, so this all races later than the check? I'm not familiar with this part of race-detection: https://github.com/golang/go/blob/master/src/testing/testing.go#L1548C1-L1549C1What did you see happen?
Tests pass and the too-late log is not caught nor is its output sent to stdout/stderr.
What did you expect to see?
should be produced reliably, as long as the test clearly finishes before the log occurs (as seen from a real-world observer, i.e. me). And it should not require outside-of-test synchronization to behave reliably.
Proof-of-concept fix
#67796
The text was updated successfully, but these errors were encountered: